Getting started
This guide takes you from zero to your first decision, executed instruction, and reported outcome. It runs against a local PayInference instance. Everything here also applies to a hosted deployment once you swap the base URL and API key.
Prerequisites#
- Node.js 20 or newer, pnpm 9
- Docker with Compose v2 (Postgres 16 and Redis 7)
1. Run PayInference locally#
pnpm install
cp .env.example .env
docker compose up -d
pnpm db:generate && pnpm db:migrate && pnpm db:seed
pnpm --filter @payinference/api dev
The Decision API listens on http://localhost:4000. The seed creates a demo workspace with merchant m_123 and a live-mode API key pi_demo_key_123 that carries every scope. See Local Setup for the full guide, ports, and troubleshooting.
2. Create your first decision#
Call the Decision API from a terminal. Note the two things every request needs: the x-api-key header and safe payment context only. Card numbers, CVVs, and emails are rejected by the schema, not ignored.
curl -s http://localhost:4000/v1/decision \
-H "content-type: application/json" \
-H "x-api-key: pi_demo_key_123" \
-d '{
"merchant_id": "m_123",
"order_id": "order_456",
"transaction": {
"amount": 14900,
"currency": "USD",
"country": "US",
"payment_method": "card",
"card_network": "visa",
"customer_type": "returning"
},
"available_providers": ["stripe", "adyen", "paypal"]
}'
The response contains exactly one instruction in action, plus the evidence behind it:
{
"decision_id": "dec_9f3a1c0b22d14e55",
"merchant_id": "m_123",
"mode": "live",
"action": "route",
"route": { "primary_provider": "adyen", "fallback_provider": "stripe" },
"risk": {
"score": 0,
"band": "low",
"recommended_action": "route",
"reason_codes": ["NORMAL_AMOUNT_FOR_MERCHANT", "RETURNING_CUSTOMER"]
},
"provider_health": {
"adyen": { "score": 94, "state": "healthy", "confidence": 91, "source": "probe" },
"stripe": { "score": 68, "state": "degraded", "confidence": 88, "source": "probe" }
},
"policy": {
"policy_id": "policy_m_123_v1",
"policy_version": "1.0.0",
"matched_rules": ["avoid_degraded_providers"]
},
"model": {
"model_version": "deterministic-v1",
"route_scores": { "adyen": 0.91, "stripe": 0.64 }
},
"reason_codes": ["ADYEN_HEALTHY_FOR_SEGMENT", "HIGHER_EXPECTED_APPROVAL_RATE", "RISK_ACCEPTABLE"],
"decision_latency_ms": 11.4,
"ttl_ms": 3000
}
3. Handle the instruction#
Your backend switches on action and executes through your own payment stack. The seven possible instructions are route, use_default_route, step_up, hold, retry, failover, and block. See Decision instructions for what each one means.
switch (decision.action) {
case 'route':
case 'failover':
return chargeWithProvider(decision.route!.primary_provider, order);
case 'use_default_route':
return chargeWithDefaultProvider(order);
case 'step_up':
return requireThreeDS(order, decision.decision_id);
case 'hold':
return parkForReview(order, decision.decision_id);
case 'retry':
return retryWithPolicy(order, decision.route);
case 'block':
return rejectPayment(order, decision.decision_id, decision.reason_codes);
}
4. Report the outcome#
After your PSP call finishes, tell PayInference what happened. This feeds provider health, analytics, and policy evaluation. It is safe to fire and forget.
curl -s http://localhost:4000/v1/outcomes \
-H "content-type: application/json" \
-H "x-api-key: pi_demo_key_123" \
-d '{
"decision_id": "dec_9f3a1c0b22d14e55",
"order_id": "order_456",
"provider_used": "adyen",
"outcome": "approved",
"provider_latency_ms": 842,
"amount": 14900,
"currency": "USD"
}'
5. Use the SDK instead#
The Node.js SDK wraps the same two calls with validation, timeouts, retries, and a local fallback for when PayInference is unreachable:
import { PayInferenceClient } from '@payinference/sdk-node';
const payinference = new PayInferenceClient({
apiKey: process.env.PAYINFERENCE_API_KEY!,
baseUrl: process.env.PAYINFERENCE_BASE_URL ?? 'http://localhost:4000',
merchantId: 'm_123',
timeoutMs: 50,
fallback: { provider: 'stripe' },
});
const decision = await payinference.decide({
order_id: 'order_456',
transaction: { amount: 14900, currency: 'USD', country: 'US', payment_method: 'card' },
available_providers: ['stripe', 'adyen', 'paypal'],
});
See the Node.js SDK guide for the full option set.
Next steps#
- Backend checkout integration: the full request path from checkout click to outcome.
- Production integration guide: timeouts, fallbacks, monitoring, and the security checklist.
- API reference: every endpoint and field.