OpenAI-compatible API
This document describes the chat completion proxy exposed by the DIMARC gateway, compatible with the OpenAI specification. It is meant to be plugged as-is into automation tools that speak to an “OpenAI API spec compatible” provider — the most common target being an AI Agent module in Make.
Prerequisites
Section titled “Prerequisites”- An active DIMARC account.
- Administrator status in your organization.
- Your authentication token (see Authentication below).
Base URL
Section titled “Base URL”https://api.dimarc.ai/openai/v1Use this versioned base (/v1) in your tools’ configuration: it matches the convention expected by OpenAI SDKs and connectors (which expect a base like https://api.openai.com/v1). The unversioned prefix https://api.dimarc.ai/openai responds in exactly the same way — kept for integrations that normalize their own base URL by appending /v1 — but it is not the one to enter.
Authentication
Section titled “Authentication”Retrieve a token via GET /v2/token (see Authentication to obtain your client_id/client_secret):
curl --location 'https://api.dimarc.ai/v2/token?client_id=your-client-id&client_secret=your-client-secret'{ "access_token": "**************", "token_type": "x-api-key", "expires_in": "3600"}Without a valid credential, any request returns 401:
{ "error": { "message": "Missing API key. Provide it in the Authorization header as 'Bearer <key>'.", "type": "invalid_request_error", "code": "invalid_api_key" }}If API access is disabled for your organization, the request returns 403 (type: "permission_error", code: "access_denied").
Available models
Section titled “Available models”| Identifier | Description |
|---|---|
dimarc-large |
Default model, best quality |
dimarc-small |
Faster/cheaper model |
These are aliases: the model actually served behind the scenes can change without notice, without breaking your integrations. An identifier outside this list is rejected with 400; an alias from the list that is momentarily not served returns 503 — a temporary outage, not a fault in your request. Query GET /openai/v1/models for the current list:
curl 'https://api.dimarc.ai/openai/v1/models' \ --header 'Authorization: Bearer <your_access_token>'{ "object": "list", "data": [ { "id": "dimarc-large", "object": "model", "created": 1732000000, "owned_by": "dimarc" }, { "id": "dimarc-small", "object": "model", "created": 1732000000, "owned_by": "dimarc" } ]}Configuring Make
Section titled “Configuring Make”- In your scenario, add an AI Agent module.
- As the LLM provider, choose OpenAI API spec compatible.
- Set the Base URL to:
https://api.dimarc.ai/openai/v1. - Set the API Key to the
access_tokenvalue obtained above (see thetoken_typewarning above — Make will send it asAuthorization: Bearer). - Choose the model:
dimarc-largeordimarc-small. - If your agent should trigger Make modules, attach them as tools: a call that results in a tool call returns
finish_reason: "tool_calls", which triggers the module’s execution.
Chat completions
Section titled “Chat completions”POST /openai/v1/chat/completionsSimple request
Section titled “Simple request”curl 'https://api.dimarc.ai/openai/v1/chat/completions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <your_access_token>' \ --data '{ "model": "dimarc-large", "messages": [ { "role": "user", "content": "Summarize this text in one sentence: ..." } ] }'{ "id": "chatcmpl-abc123", "object": "chat.completion", "model": "dimarc-large", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 42, "completion_tokens": 18, "total_tokens": 60 }}Request with tools (tools)
Section titled “Request with tools (tools)”curl 'https://api.dimarc.ai/openai/v1/chat/completions' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <your_access_token>' \ --data '{ "model": "dimarc-large", "messages": [ { "role": "user", "content": "What is the weather like in Lyon?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Gives the current weather for a city", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ] }'{ "choices": [ { "message": { "role": "assistant", "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Lyon\"}" } } ] }, "finish_reason": "tool_calls" } ]}Streamed request (stream: true)
Section titled “Streamed request (stream: true)”curl 'https://api.dimarc.ai/openai/v1/chat/completions' \ --no-buffer \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <your_access_token>' \ --data '{ "model": "dimarc-large", "messages": [{ "role": "user", "content": "Hello" }], "stream": true }'Streamed text/event-stream response, terminated by data: [DONE]:
data: {"id":"chatcmpl-abc123","choices":[{"delta":{"content":"Hello"}}]}
data: {"id":"chatcmpl-abc123","choices":[{"delta":{"content":"!"}}]}
data: [DONE]If generation fails after the stream has started — model error, upstream connection loss, a prolonged silence from the model, or a generation cut short — the HTTP status is already 200: the incident is reported through an OpenAI-formatted error frame, followed by data: [DONE].
data: {"error":{"message":"The model backend returned an error.","type":"api_error","code":"upstream"}}
data: [DONE]So treat a frame carrying error as an abnormal end of generation: the content received before it is partial. The message is constant: the technical detail stays on the DIMARC side.
Parameters
Section titled “Parameters”Relayed as-is
Section titled “Relayed as-is”messages (required), tools, tool_choice, temperature, top_p, max_completion_tokens, max_tokens, presence_penalty, frequency_penalty, stop, stream, stream_options, response_format.
chat_template_kwargs is also relayed when provided: it is an advanced parameter specific to the underlying engine. When absent, the gateway forces it to { "enable_thinking": false } to disable extended reasoning by default; provide it explicitly to re-enable it.
stream
Section titled “stream”Accepted values: true (SSE stream), false, absent, or explicitly null (these last three are treated identically: a regular, non-streamed JSON response). Any other value (string, number, object…) is rejected:
{ "error": { "message": "The 'stream' parameter must be a boolean.", "type": "invalid_request_error", "code": "invalid_value" }}→ 400. This rejection happens before any call to the model: no usage is billed.
Rejected
Section titled “Rejected”| Parameter | Rejection condition |
|---|---|
n |
Value strictly greater than 1 (only n: 1, the default, is accepted) |
logprobs |
Any defined value |
logit_bias |
Any defined value |
These rejections return 400:
{ "error": { "message": "The 'n' parameter is not supported.", "type": "invalid_request_error", "code": "unsupported_parameter" }}Limits
Section titled “Limits”- Request size: 2 MB (2,097,152 bytes, measured on the
Content-Lengthheader). Beyond that, the gateway returns413(code: "request_too_large") before even reading the body. A request with a body that does not declare its length — a body sent in chunks (Transfer-Encoding: chunked) — is refused with411(code: "missing_content_length"): OpenAI SDKs and connectors like Make serialize their body and always declare that length. - Output tokens: capped at 8192 per response. Both
max_completion_tokens(current name) andmax_tokens(deprecated) are accepted and capped independently; a value above the cap is silently clamped to 8192 — this is not a rejection. If neither is provided, the response is bounded to 8192. When both are provided,max_completion_tokenswins. - Tokens: usage counts against the token quota included in your subscription, assessed on the calendar-month total across all billable channels (public API and public channel). Beyond it, overage is billed on usage, as on the rest of the public API.
- Spending limit: your organization can set a monthly overage cap, in euros, from its subscription settings. Once reached, requests are refused with
429(code: "spending_limit_reached") until the next period or until the cap is raised. With no cap set, no amount limit applies. The model list stays reachable so your client can still configure itself. - Concurrent generations: at least 4 per organization. Beyond that,
429(code: "concurrent_limit_exceeded") — retry once a running generation completes. - Stream duration: 5 minutes. A stream exceeding that duration is interrupted — the error frame then
data: [DONE]are emitted, and the tokens produced so far are billed. - Rate: 100 requests per minute per organization, across all of your tokens — obtaining a new token does not reset the counter. Beyond that,
429with aRetry-Afterheader (seconds until the next window):
{ "error": { "message": "Rate limit reached. Please slow down your requests.", "type": "rate_limit_error", "code": "rate_limit_exceeded" }}Error format
Section titled “Error format”Unlike the rest of the DIMARC API ({status, code, error, detail} envelope), this endpoint strictly follows the OpenAI error format:
{ "error": { "message": "...", "type": "...", "code": "..." }}| Status | Code | Type | Case |
|---|---|---|---|
| 400 | model_not_found |
invalid_request_error |
Model identifier outside the GET /openai/v1/models list |
| 400 | unsupported_parameter |
invalid_request_error |
n > 1, logprobs, or logit_bias provided |
| 400 | invalid_value |
invalid_request_error |
stream is neither a boolean, absent, nor null |
| 400 | invalid_request |
invalid_request_error |
Invalid body: malformed JSON, messages missing or empty |
| 401 | invalid_api_key |
invalid_request_error |
API key missing or invalid |
| 403 | access_denied |
permission_error |
API access disabled for the organization, or organization without a subscription |
| 404 | not_found |
invalid_request_error |
Unknown path under /openai, or wrong HTTP method on a known path |
| 411 | missing_content_length |
invalid_request_error |
Request with a body and no usable Content-Length header |
| 413 | request_too_large |
invalid_request_error |
Request body larger than 2 MB |
| 429 | rate_limit_exceeded |
rate_limit_error |
More than 100 requests/minute for this organization |
| 429 | concurrent_limit_exceeded |
rate_limit_error |
Too many concurrent generations for this organization |
| 429 | spending_limit_reached |
insufficient_quota |
Organization spending limit reached |
| 500 | internal_error |
api_error |
Unexpected internal failure: retrying is unlikely to change anything. The technical detail is never returned, it stays on the DIMARC side |
| 502 | upstream |
api_error |
The model returned an error |
| 503 | unavailable |
api_error |
Temporary outage: model advertised but not served, unreachable, or an internal dependency failing — retry after the delay advertised by the Retry-After header |
| 504 | timeout |
api_error |
The model did not respond in time |
Support and assistance
Section titled “Support and assistance”For any questions regarding the OpenAI-compatible API, contact our support team at contact@dimarc.fr