API Reference
No SDK required. No npm install. Every endpoint works with plain curl or the built-in fetch in Node.js 18+. Authenticate with your API key in the x-api-key header.
Authentication
All protected endpoints require your API key sent as an HTTP header. You get your key when you register.
x-api-key: ck_your_api_key_hereKeys are prefixed with
ck_ and shown once at registration. Store them securely.
Base URL
All requests go to:
GET /health
Public. Check that the API is up. No authentication required.
curl https://api.comorando.com/healthResponse
POST /api-keys/register
Public. Create an organization and get your API key in one step. The key is shown once — save it immediately.
| Field | Type | Description |
|---|---|---|
| email* | string | Your email address |
| name* | string | Your organization name (min 2 chars) |
curl -X POST https://api.comorando.com/api-keys/register \ -H 'Content-Type: application/json' \ -d '{"email":"you@example.com","name":"Acme Inc"}'
const res = await fetch('https://api.comorando.com/api-keys/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'you@example.com', name: 'Acme Inc' }) }); const { organizationId, apiKey, plan } = await res.json(); // Save apiKey — it's only shown once
Response 201
POST /decisions
Submit a payment or subscription event for AI analysis and automated handling. The response is immediate — execution happens asynchronously.
| Field | Type | Description |
|---|---|---|
| event_type* | string | Type of event: payment.failed, subscription.cancelled, subscription.expired, etc. |
| event_idoptional | string | Unique ID for idempotency. Duplicate event_ids are silently ignored within 1 hour. |
| dataoptional | object | Any event payload: customer ID, amount, plan, failure reason, etc. |
curl -X POST https://api.comorando.com/decisions \ -H 'Content-Type: application/json' \ -H 'x-api-key: ck_your_key_here' \ -d '{ "event_type": "payment.failed", "event_id": "paypal-evt-abc123", "data": { "customer_email": "user@example.com", "amount": 79.00, "currency": "USD", "failure_reason": "insufficient_funds" } }'
const res = await fetch('https://api.comorando.com/decisions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.COMORANDO_API_KEY }, body: JSON.stringify({ event_type: 'payment.failed', event_id: webhookEvent.id, // ensures exactly-once data: webhookEvent }) }); const { id, status, correlation_id } = await res.json();
Response 201
GET /decisions
List decisions for your organization, ordered by most recent. Supports cursor-based pagination.
| Query param | Type | Description |
|---|---|---|
| limitoptional | number | Max results to return. Default: 20 |
| cursoroptional | string | ISO timestamp from previous response's next_cursor for pagination |
curl 'https://api.comorando.com/decisions?limit=10' \ -H 'x-api-key: ck_your_key_here'
const res = await fetch('https://api.comorando.com/decisions?limit=10', { headers: { 'x-api-key': process.env.COMORANDO_API_KEY } }); const { data, next_cursor } = await res.json();
Response 200
GET /decisions/:id
Retrieve a single decision by its ID.
curl https://api.comorando.com/decisions/bf56b6e4-20e0-4bce-8109-852493458072 \ -H 'x-api-key: ck_your_key_here'
const res = await fetch(`https://api.comorando.com/decisions/${id}`, { headers: { 'x-api-key': process.env.COMORANDO_API_KEY } }); const { data } = await res.json();
Response 200
PATCH /decisions/:id
Update a decision's fields. Setting status to resolved triggers the execution engine.
curl -X PATCH https://api.comorando.com/decisions/bf56b6e4-20e0-4bce-8109-852493458072 \ -H 'Content-Type: application/json' \ -H 'x-api-key: ck_your_key_here' \ -d '{"status":"resolved"}'
const res = await fetch(`https://api.comorando.com/decisions/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.COMORANDO_API_KEY }, body: JSON.stringify({ status: 'resolved' }) }); const { data } = await res.json();
GET /status/data
Public. Returns infrastructure health: API uptime, Redis status, Supabase status, Gemma latency, and the 10 most recent decisions.
curl https://api.comorando.com/status/dataResponse 200
GET /billing/usage
Returns your organization's current plan, event usage, and overage details for the current billing period.
curl https://api.comorando.com/billing/usage \ -H 'x-api-key: ck_your_key_here'
const res = await fetch('https://api.comorando.com/billing/usage', { headers: { 'x-api-key': process.env.COMORANDO_API_KEY } }); const usage = await res.json();
Retry Guidelines
Comorando's default retry schedule is designed to comply with PayPal AUP section 4.3 and equivalent processor policies. You may customize intervals via your decision configuration, but must remain within your processor's acceptable use boundaries.
| Attempt | Default Interval | Notes |
|---|---|---|
| First retry | 1 hour after initial failure | Covers transient declines (temporary holds, network issues) |
| Second retry | 24 hours after first retry | Allows time for customer to update payment method |
| Third retry | 72 hours after second retry | Final automated attempt before escalation or grace period |
Event types
Use these as the event_type field when submitting decisions.
| event_type | Description |
|---|---|
| payment.failed | A payment attempt was declined or failed |
| payment.reversed | A charge was reversed or refunded |
| subscription.cancelled | A subscription was cancelled by the user or gateway |
| subscription.expired | A subscription reached end of billing period |
| subscription.suspended | A subscription was suspended due to payment failure |
| checkout.abandoned | A checkout session was started but not completed |
Error codes
| Code | HTTP | Meaning |
|---|---|---|
| unauthorized | 401 | Missing or invalid API key |
| event_type_required | 400 | The event_type field is missing |
| email_already_registered | 409 | That email is already registered |
| valid_email_required | 400 | The email field is missing or invalid |
| organization_name_required | 400 | The name field is missing or too short |
| duplicate_ignored | 200 | Event with this event_id was already processed (idempotent) |
| not_found | 404 | Decision ID not found or belongs to another org |
| rate_limit_exceeded | 429 | Too many requests — slow down |
| internal_error | 500 | Server-side error — contact support |
Need help? hello@comorando.com