Five ways to describe your API. One single model out.
MCP server, OpenAPI, GraphQL, ready-made connector or manual entry: everything ends up in the same catalogue, and nothing is exposed until it is ticked.
# Report an event: Nodium checks and files it, sending nothing yetcurl https://nodium.io/api/v1/templates/outbound \ -H "Authorization: Bearer nod_••••••••" \ -H "Content-Type: application/json" \ -d '{ "externalId": "order-2481-shipped", "eventType": "order.shipped", "phone": "+33 6 00 00 00 00", "templateName": "order_shipped", "payload": { "reference": "2481" } }'{ "event": { "externalId": "order-2481-shipped", "eventType": "order.shipped", "status": "scheduled", "skipReason": null, "estimatedCostUsd": null }, "duplicate": false, "caller": "machine", "skipReasons": []}The integration journey
Six moves, from the key to the first event. None makes visible what nobody has ticked.
Create an API key
In the console: Account › Advanced › API keys. The key is shown only once, acts on behalf of its creator and carries a role capped by theirs.
Authorization: Bearer nod_…Connect your software
Pick one of the five sources and drop in its authentication: it is encrypted and never comes back out of a read.
Test the connection
A failure comes back with a readable diagnosis, not an error. An address leading to a private network is refused.
Describe the catalogue
Automatic for an MCP server and an OpenAPI description, by hand for the others: objects, fields, operations.
POST /api/v1/connectors/:id/discoverTick what is allowed
Discovery writes everything as no. Your customer confirms; a write is born switched off and requires a human's approval.
Report your events
Your software announces a fact; Nodium checks the contact, their consent, the template and the channel, estimates the cost and files it. Your webhooks keep you informed.
POST /api/v1/templates/outbound
The five sources
What each one asks for, and what it can do on its own.
Ready-made connector
Your Shopify shop domain and a token.
MCP server
The address of your MCP endpoint.
OpenAPI description
The address of the OpenAPI file itself, not of the documentation page.
GraphQL schema
The address of the endpoint, the one that receives the queries.
Manual entry
Nothing to publish: your objects are described one line per field.
Why we start with MCP
- Because tool descriptions carry meaning and not only shape. That is the weakness of an OpenAPI description: it says how to call, without saying what the call means.
- Because the input schema of an MCP tool is already JSON Schema, so exactly our format. It is copied across as is: no conversion, therefore no loss.
- Because the tool list is a living discovery. You add a tool, a new discovery adds it — without ever unticking what your customer had confirmed, or renaming what they had renamed.
The confirmation screen
Discovery proposes, your customer confirms. Everything found is written as no: no field is visible, no operation is callable until it has been ticked. The screen arrives pre-ticked on a handful of fields, writing off, and one can move on without touching anything.
- The field that serves as the reference, and those that identify an end customer.
- Sensitive fields, never proposed as exposed, and masked in the logs.
- The operations allowed, and those that require a human to approve.
- A read that became a write at the next discovery is switched off outright: nobody had accepted that one.
Three families of call
At run time, everything comes down to these three.
searchSearch
Find the object the conversation is about, from a phone number, an email address or a reference.
readRe-read
Read an already attached object again, so the answer is about its current state and not a memory of it.
executeExecute
Act in your software. Switched on operation by operation, with a mandatory deduplication key: a replayed call never charges twice.
Off by default
Calling Nodium from your software
Your system has no session: it identifies itself with an API key and reports an event — an order shipped, a deadline coming up. Nodium checks the contact, their consent, the existence of an approved template, the channel, and then estimates the cost. That call sends nothing: it decides.
- The same event twice goes out once: the call is idempotent on the identifier you supply, and replays the original decision.
- A key that is presented and wrong is refused on the spot. Never a quiet fallback to a session: an expired key must be visible immediately.
- A refusal states everything that was missing, not just the first reason.
- The cost is estimated before sending. A price we do not know is called unknown, never free.
# HTTP 200: the event is filed, nothing is sent{ "event": { "externalId": "order-2482-shipped", "status": "skipped", "skipReason": "no_consent" }, "duplicate": false, "caller": "machine", "skipReasons": ["no_consent", "template_not_approved"]}Staying informed: webhooks
A subscription, created in the console or through the API, receives the events it chose as POST requests. Every delivery is signed; answer with a 2xx code.
The events
- message.received
- message.sent
- approval.requested
- approval.decided
- mission.closed
- dossier.changed
- timer.fired
Without a 2xx answer, the delivery is retried: six attempts at most, after 1 min, 5 min, 30 min, 2 h and then 12 h.
The signing secret is returned only once, when the subscription is created. The signature carries the sending time and an HMAC-SHA256 of the time and the body.
import { createHmac, timingSafeEqual } from 'node:crypto'// Reject any delivery whose signature does not matchexport function isFromNodium(header, rawBody, secret) { const sig = Object.fromEntries(header.split(',').map(p => p.split('='))) const expected = createHmac('sha256', secret) .update(`${sig.t}.${rawBody}`) .digest('hex') return sig.v1?.length === expected.length && timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected))}Quick reference
What holds for every call, in both directions.
Calling the Nodium API
- Address
https://nodium.io/api/v1/…A route that changes shape will move to v2 without breaking v1.- Authentication
Authorization: Bearer nod_…A key acts on behalf of its creator, with a role capped by theirs; everything is logged in their name.- Isolation
- The key designates its workspace. A resource from another workspace answers 404, never 403.
- Rate
- 600 calls per minute per key; beyond that, 429 with the time to wait.
- Idempotency
- An event replays on its externalId, a message send on its idempotencyKey: the same key returns the same result.
- Errors
- JSON with statusCode and statusMessage: a message in French that can be displayed as is, and a code when a program must react differently.
- Pagination
- By cursor, never by page number: a queue moves under your fingers.
When Nodium calls your API
Five ways to authenticate, the ones APIs actually use: no authentication, a token presented as an Authorization Bearer, a key in a header you name, a username and password pair, or an OAuth 2 token pasted by hand.
What we do with your secrets
- The authentication secret is encrypted and never comes back out. A read only says whether there is one.
- A key placed in a field that was not meant for it is refused, together with the place where it belongs.
- Nothing crosses the wall between workspaces. An identifier belonging to someone else answers not found, never forbidden.
- An address pointing at a private network is refused when the connection is tested.
- Fields marked as sensitive are masked in the call logs.
What we cannot do yet
The list is short and kept current. A limit written down costs less than a limit discovered.
- Automatic discovery only exists for MCP servers and OpenAPI descriptions. A GraphQL schema can be tested, but its catalogue is described by hand.
- The older two-address MCP transport is not supported.
- No OAuth 2 token renewal.
- Every MCP call reopens a handshake: slightly slower, but nothing to repair when your server restarts.
- Sensitive data sitting in a field nobody marked as such is logged in clear. Discovery proposes the marking, your customer completes it.
Connect your API
Register a source, test it, then discover its catalogue — three moves, from one screen.