Create a workspace
Start with a sandbox workspace. It holds your API keys, provider settings, callback URLs, and audit trail.

Constra gives product teams one operational layer for payment intents, provider callbacks, recovery actions, and audit trails. Start in simulator mode, validate the workflow with your application, then connect approved provider credentials when your pilot is ready.
Quickstart
Your application only needs a Constra API base URL, a workspace secret key, and a webhook secret. Provider credentials such as Daraja keys are configured inside Constra so your app does not have to own every rail-specific integration.
.env
bash
CONSTRA_API_BASE_URL=https://api.constra.online/v1
CONSTRA_SECRET_KEY=cs_test_your_workspace_secret
CONSTRA_WEBHOOK_SECRET=whsec_your_callback_secret
CONSTRA_DEFAULT_PROVIDER=mpesa
CONSTRA_ENVIRONMENT=sandboxStart with a sandbox workspace. It holds your API keys, provider settings, callback URLs, and audit trail.
Your application sends amount, customer, provider, and reference data to Constra instead of talking to every rail directly.
Constra normalizes provider callbacks into stable events such as succeeded, failed, cancelled, timeout, or review_required.
Agents can draft recovery notes, retry suggestions, and operator summaries while deterministic APIs own execution.
Payment Intents
A payment intent is the source of truth for one attempted payment. It keeps the customer action, provider response, retry history, and agent review notes together under one id.
Create intent
curl
curl -X POST https://api.constra.online/v1/payment-intents \
-H "Authorization: Bearer cs_test_your_workspace_secret" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order_7429_deposit" \
-d '{
"amount": 1250,
"currency": "KES",
"provider": "mpesa",
"customer": {
"name": "Amina N.",
"phone_number": "254700000000"
},
"reference": "order_7429",
"description": "Solar home kit deposit",
"agent_policy": "operator_review"
}'Response
json
{
"id": "pi_01hx9k7s4v3p9e7m5n2",
"status": "pending_user_action",
"amount": 1250,
"currency": "KES",
"provider": "mpesa",
"reference": "order_7429",
"provider_action": {
"type": "stk_push",
"state": "sent_to_customer",
"checkout_request_id": "ws_CO_120520261644291"
},
"next_action": "wait_for_callback"
}Node.js
javascript
const response = await fetch("https://api.constra.online/v1/payment-intents", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CONSTRA_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order_7429_deposit"
},
body: JSON.stringify({
amount: 1250,
currency: "KES",
provider: "mpesa",
customer: { phone_number: "254700000000" },
reference: "order_7429",
description: "Solar home kit deposit",
agent_policy: "operator_review"
})
});
const intent = await response.json();Python
python
import os
import requests
response = requests.post(
"https://api.constra.online/v1/payment-intents",
headers={
"Authorization": f"Bearer {os.environ['CONSTRA_SECRET_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": "order_7429_deposit",
},
json={
"amount": 1250,
"currency": "KES",
"provider": "mpesa",
"customer": {"phone_number": "254700000000"},
"reference": "order_7429",
"description": "Solar home kit deposit",
"agent_policy": "operator_review",
},
)
intent = response.json()Callbacks
Provider callbacks are often inconsistent. Constra converts them into stable webhook events so your backend can react with simple, predictable handlers.
payment_intent.createdConstra accepted the request and created an auditable intent.
payment_intent.pending_user_actionA customer action is required, such as approving an STK push.
payment_intent.succeededThe provider confirmed successful payment.
payment_intent.requires_recoveryThe provider returned a recoverable issue such as cancellation or timeout.
payment_intent.failedThe provider returned a terminal failure or the attempt exhausted retries.
Webhook payload
json
{
"id": "evt_01hx9m4b9s8n2",
"type": "payment_intent.requires_recovery",
"created_at": "2026-05-15T13:41:08Z",
"data": {
"payment_intent_id": "pi_01hx9k7s4v3p9e7m5n2",
"status": "requires_recovery",
"provider": "mpesa",
"provider_result_code": "1032",
"provider_result_desc": "Request cancelled by user.",
"agent_note": "Customer cancelled the prompt. Offer retry or alternate payment timing."
}
}Verify signature
javascript
import crypto from "node:crypto";
export function verifyConstraWebhook(rawBody, signature, secret) {
const digest = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest)
);
}Agent Review
Constra treats agents as operators with bounded tools. They can explain a failed callback, recommend a retry, prepare a dispute note, or ask for human approval. The deterministic backend still validates state, idempotency, provider credentials, and execution rules.
No prompt, chat message, or generated answer should directly post funds. Constra converts agent suggestions into reviewable actions before a provider call is made.
Simulate a recoverable provider outcome
curl
curl -X POST https://api.constra.online/v1/payment-intents/pi_01hx9k7s4v3p9e7m5n2/simulate-callback \
-H "Authorization: Bearer cs_test_your_workspace_secret" \
-H "Content-Type: application/json" \
-d '{
"result_code": 1032,
"result_desc": "Request cancelled by user."
}'API Reference
The current simulator implements the core payment-intent and callback loop. The same resource shape is designed to support Daraja sandbox, Paystack test mode, and future provider adapters.
/v1/payment-intentsCreate a new payment intent for mobile money, card, wallet, or another configured rail.
Simulator/v1/payment-intents/{id}Retrieve the latest state, provider reference, amount, customer, and recovery summary.
Simulator/v1/payment-intents/{id}/eventsRead the full event timeline for reconciliation, debugging, and audit review.
Simulator/v1/payment-intents/{id}/simulate-callbackApply a sandbox outcome such as success, cancellation, timeout, or insufficient funds.
Simulator/v1/providers/mpesa/callbackReceive Daraja-style provider callbacks and map them into Constra payment events.
Sandbox rail/v1/sandbox/overviewReturn workspace stats, recent intents, callback volume, and operational activity.
SimulatorGo Live
For M-Pesa, your team creates a Daraja app, adds the sandbox or production credentials into Constra, and points provider callbacks to the Constra callback URL for your workspace.
1. Simulator: test product logic and operator workflows.
2. Provider sandbox: receive real provider payloads with no live settlement.
3. Pilot: route limited production transactions with monitoring and review.
Provider
M-Pesa Daraja
Mode
Sandbox first, production after provider approval
Business Short Code
174379 for Daraja sandbox
Callback URL
Constra generates a provider callback URL for the workspace
Account Reference
Use your order id, invoice id, or customer reference
Credential Storage
Provider secrets stay server-side and move to Key Vault for Azure deployment