REST API with JWT authentication. 38-feature ML scoring, SHAP explanations, label feedback loop, and real-time drift monitoring — all in one endpoint.
fsk_live_ keys) and requires a 38-element features array — not a transaction-field object. See the Feature Schema section below.Every API call (except GET /health and GET /info) requires a JWT Bearer token. Obtain one by logging in with your Remorant email and password. Tokens expire after 24 hours.
| Role | Can predict | Can label | Can read stats | Admin |
|---|---|---|---|---|
| platform_admin | ✓ | ✓ | ✓ | ✓ Full |
| tenant_admin | ✓ | ✓ | ✓ | ✓ Tenant |
| analyst | ✓ | ✓ | ✓ | — |
| integration | ✓ | ✓ | — | — |
| readonly | — | — | ✓ | — |
Machine-to-machine integrations should use a user account with the integration role. Create one in the admin panel under Team Management.
Login → build feature vector → score. All examples call the real API endpoint.
curl -X POST https://remorant.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "you@yourcompany.com",
"password": "your-password"
}'{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": { "id": "usr_...", "email": "you@yourcompany.com", "role": "integration" },
"tenant": { "id": "ten_...", "name": "Your Company", "plan": "growth" }
}# TOKEN from Step 1 response
curl -X POST https://remorant.com/api/v1/predict \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"features": [0, -0.31, 1.19, 1.03, 0.99, 0.84, -0.11, 0.42, 0.16, 0.07, 0.06, -0.34, 0.34, -0.2, 0.21, 0.09, 0.42, 0.15, 0.01, -0.13, -0.04, -0.08, -0.15, 0.02, -0.05, -0.21, -0.07, 0.11, -0.05, 47.5, 14, 0.4, 3.87, 0, 0, 0.2, 0, 3.87],
"transaction_id": "txn_abc123"
}'{
"request_id": "req_7f3a9e2d",
"transaction_id": "txn_abc123",
"fraud_probability": 0.0842,
"is_fraud": false,
"risk_level": "low",
"recommended_action": "ALLOW",
"threshold": 0.5802,
"threshold_source": "tenant_optimized",
"model_version": "1.0.0",
"latency_ms": 38,
"explanation": {
"top_features": [
{ "feature": "V14", "shap_value": -0.18, "value": 0.21 },
{ "feature": "Amount", "shap_value": 0.05, "value": 47.5 },
{ "feature": "V17", "shap_value": -0.03, "value": 0.15 }
]
}
}# After a chargeback or manual review, send the confirmed outcome back.
# This is used for model drift monitoring and future retraining.
curl -X POST https://remorant.com/api/v1/label \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"request_id": "req_7f3a9e2d",
"actual_label": 0
}'
# actual_label: 1 = confirmed fraud, 0 = confirmed legitimateThe features array must contain exactly 38 floats in the canonical order below. The authoritative column list is always available at GET https://remorant.com/info → feature_columns.
/api/v1/auth/loginpublicExchange email + password for a JWT token (24h expiry)/api/v1/predictJWT requiredScore a transaction. Body: { features: number[38], transaction_id?: string }/api/v1/batchJWT requiredBatch scoring, up to 1 000 transactions per call/api/v1/labelJWT requiredSubmit confirmed outcome: { request_id, actual_label: 0|1 }/api/v1/statsJWT requiredPrediction statistics for your tenant/infopublicModel metadata: version, feature_columns, threshold, metrics/healthpublicLiveness probe — returns { status: "ok" }/api/v1/healthpublicDetailed service health: API, database, cache, model registry status and uptime/readypublicReadiness probe — model and database must be operational/metricspublicInfrastructure metrics endpoint (available on Enterprise plans)Rate limits are enforced per API credential using sliding-window counters. Limits reset on a rolling basis — exceeding your limit returns HTTP 429 with a Retry-After header indicating when you may resume.
| Plan | Per minute | Per hour | Per day |
|---|---|---|---|
| Trial | 20 | 200 | 1,000 |
| Starter | 100 | 2,000 | 10,000 |
| Growth | 500 | 10,000 | 50,000 |
| Enterprise | 2,000 | 40,000 | 500,000 |
Rate limit headers returned on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. On 429, also Retry-After (seconds).
Add "is_sandbox": true to any POST /api/v1/predict request during development and QA. Sandbox calls return the exact same response format as production but are never persisted, never billed, and never affect your analytics or drift monitoring.
curl -X POST https://remorant.com/api/v1/predict \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"features": [0, -0.31, 1.19, 1.03, 0.99, 0.84, -0.11, 0.42, 0.16, 0.07, 0.06, -0.34, 0.34, -0.2, 0.21, 0.09, 0.42, 0.15, 0.01, -0.13, -0.04, -0.08, -0.15, 0.02, -0.05, -0.21, -0.07, 0.11, -0.05, 47.5, 14, 0.4, 3.87, 0, 0, 0.2, 0, 3.87],
"transaction_id": "test_txn_dev_001",
"is_sandbox": true
}'
# Sandbox predictions:
# Same response format as production
# NOT saved to the database
# NOT counted toward your billing quota
# NOT included in analytics or drift monitoring
# Omit is_sandbox (or set false) in productionAll errors return a structured JSON body. Handle errors by error code, not by HTTP status alone — multiple error codes can share the same HTTP status.
{ "error": "MISSING_FEATURES", "message": "features must contain exactly 38 numeric values" }| Status | Error code | Cause | Recommended action |
|---|---|---|---|
| 400 | MISSING_FEATURES | features array is absent or does not contain exactly 38 elements | Validate array length before sending |
| 400 | INVALID_FORMAT | features contains non-numeric values or request body is invalid JSON | Ensure every element is a finite float |
| 400 | INVALID_INPUT | Request body fails schema validation | Check field names and types against the API reference |
| 401 | AUTHENTICATION_FAILED | JWT token is missing, malformed, or has expired (24 h TTL) | Re-authenticate via POST /api/v1/auth/login and retry |
| 401 | INVALID_CREDENTIALS | Email or password is incorrect | Verify credentials — do not retry in a tight loop |
| 403 | ACCOUNT_DISABLED | Account has been suspended | Contact support@remorant.com |
| 403 | INSUFFICIENT_PERMISSIONS | Token role cannot perform this action | Use a token with the integration or analyst role |
| 429 | RATE_LIMIT_EXCEEDED | Sliding-window rate limit hit for your plan | Read Retry-After header and wait before retrying |
| 503 | MODEL_NOT_AVAILABLE | Prediction model is temporarily unavailable | Check GET /health — contact support if the outage persists |
| 500 | PREDICTION_ERROR | Unexpected internal error during scoring | Retry with exponential backoff; open a support ticket if it persists |
Remorant signs every webhook delivery with an HMAC-SHA256 signature in the X-Remorant-Signature header. Always verify the signature before processing the payload.
| transaction.fraud_detected | Fraud probability exceeds 0.80 |
| transaction.high_risk | Risk level is high or critical |
| transaction.blocked | Recommended action is BLOCK |
| drift.detected | Feature distribution drift detected |
| rate_limit.exceeded | Tenant rate limit was hit |
Subscribe to events in Settings → Webhooks.
import hmac, hashlib, os
from flask import Flask, request
def verify_signature(payload_bytes: bytes, header_sig: str, secret: str) -> bool:
"""Return True if the webhook signature is valid."""
expected = hmac.new(
secret.encode(),
payload_bytes,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, header_sig)
app = Flask(__name__)
@app.route("/remorant-webhook", methods=["POST"])
def handle_webhook():
ok = verify_signature(
request.get_data(), # raw bytes — before JSON parsing
request.headers.get("X-Remorant-Signature", ""),
os.environ["REMORANT_WEBHOOK_SECRET"],
)
if not ok:
return {"error": "Invalid signature"}, 401
event = request.json
if event["event_type"] == "transaction.fraud_detected":
handle_fraud_alert(event["data"])
elif event["event_type"] == "transaction.blocked":
handle_blocked(event["data"])
elif event["event_type"] == "drift.detected":
notify_ops_team(event["data"])
return {"received": True}, 200import crypto from 'crypto';
import express from 'express';
function verifySignature(rawBody, headerSig, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// timingSafeEqual prevents timing-based attacks
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(headerSig));
}
const app = express();
// Use express.raw() to preserve raw bytes for signature verification
app.post('/remorant-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-remorant-signature'] ?? '';
if (!verifySignature(req.body, sig, process.env.REMORANT_WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
switch (event.event_type) {
case 'transaction.fraud_detected': handleFraudAlert(event.data); break;
case 'transaction.blocked': handleBlocked(event.data); break;
case 'drift.detected': notifyOps(event.data); break;
}
res.json({ received: true });
});express.raw() in Node.js or request.get_data() in Flask.Test real fraud detection scenarios interactively with live results and SHAP explanations.
Receive real-time fraud events over HTTPS with HMAC-SHA256 signature verification.
Live fraud rates, SHAP feature trends, drift alerts, and model performance.
Detailed docs are available in the repo at docs/. An interactive OpenAPI spec is on the roadmap.
Python SDK at sdks/python/ and JS SDK at sdks/javascript/ are available in the repo. A high-level check_transaction() interface is on the roadmap pending a server-side feature builder endpoint.
Need help mapping your card-network fields to the feature vector? Contact our integrations team.
Create your account, get a JWT, and make your first prediction in under 5 minutes.