AI Knowledge & Logic

Custom HTTP Endpoints

Create a URL backed by JavaScript/TypeScript for forms, callbacks, and human-driven automations, without a deployment.

A custom HTTP endpoint runs your JavaScript/TypeScript function when its URL receives a request. Use it for a help-center form, a warehouse decision, or a small integration callback. Changes take effect on the next request, without deploying code.

Create an endpoint

Open Settings → Advanced → HTTP Endpoints, select Create endpoint, and enter a name and JavaScript/TypeScript code. Select the allowed methods and save. Copy the generated URL from the editor.

Endpoints belong to the selected business. Their URLs remain stable when you rename or edit them. Disable an endpoint to stop execution immediately; disabled and deleted URLs return 404.

import { httpResponse, type HttpEndpointContext } from "octocom";

export async function handle(context: HttpEndpointContext) {
  const body = context.request.body;
  if (
    !body ||
    typeof body !== "object" ||
    !("name" in body) ||
    typeof body.name !== "string"
  ) {
    return httpResponse({ error: "Please provide your name" }, { status: 422 });
  }
  return { message: `Hello, ${body.name}!` };
}

POST JSON to the URL:

const response = await fetch(endpointUrl, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Alex" }),
  credentials: "omit",
});
const result = await response.json();

Browser cross-origin requests and preflight requests are handled by Octocom. Preflight requests do not run JavaScript/TypeScript. These endpoints do not use dashboard login cookies as authentication.

GET and POST

POST is the default. Use it to submit forms, change state, or trigger actions. Enable GET when you need to retrieve data. The endpoint receives the actual method; unconfigured methods return 405 without executing JavaScript/TypeScript.

Do not perform mutations on GET. An email button should open a page where a confirmation button sends POST. Merely opening a link, including an automated preview, should not make the decision.

PUT, PATCH, DELETE, and HEAD are not invocation methods in this version.

Request context

Export handle(context) from a JavaScript or TypeScript module. TypeScript is transpiled automatically and runs on Cloudflare Workers; Python is not supported for HTTP endpoints. Import helpers such as getSecret, httpResponse, and octocomApi from "octocom"; import shared JavaScript modules from "modules/<name>". Helpers that call APIs return promises: use await.

See the JavaScript sandbox playbook. Use the SDK's HttpEndpointContext type for the request contract. Native fetch and Web Crypto are available; arbitrary npm imports are not.

FieldValue
context.businessBusiness name and slug, resolved by Octocom
context.request.idUnique request ID
context.request.methodHTTP method
context.request.headersHeaders with lowercase names
context.request.queryQuery values; repeated parameters become arrays
context.request.bodyParsed JSON, parsed URL-encoded form, text, or null for an empty body
context.request.rawBodyBody decoded as UTF-8
context.request.rawBodyBase64Exact request bytes encoded as base64, for signature verification

JSON content types include application/json and +json. Malformed JSON returns 400. Multipart uploads are not parsed into files; upload files through the existing file API and submit references instead.

The infrastructure-only x-origin-auth header is not exposed to JavaScript/TypeScript. Caller input cannot replace trusted business or organization context. There is no automatically selected conversation or customer: a conversation ID in the body is untrusted input, and your code must check whether the caller may act on it before using conversation helpers.

Authentication is your code

Invocation URLs have no built-in authentication. Public contact forms can accept public submissions. If your endpoint needs authentication, verify it at the beginning of handle, before any side effects.

For a server-to-server token check, store WAREHOUSE_ENDPOINT_TOKEN in Secrets, then:

import { getSecret, httpResponse, type HttpEndpointContext } from "octocom";

export async function handle(context: HttpEndpointContext) {
  const supplied = context.request.headers.authorization;
  const expected = "Bearer " + (await getSecret("WAREHOUSE_ENDPOINT_TOKEN"));
  if (typeof supplied !== "string" || supplied !== expected) {
    return httpResponse({ error: "Unauthorized" }, { status: 401 });
  }
  return { accepted: true };
}

For signed callbacks, use Web Crypto's verification APIs with the exact request bytes.

Do not embed a reusable secret in public HTML. For signed callbacks, decode rawBodyBase64 and verify the signature against those exact bytes, following the sender's protocol. Query parameters and headers are not trusted merely because they exist.

Responses

Return any JSON-serializable value for a 200 response. To choose the status or supported headers, use:

import { httpResponse } from "octocom";

export function handle() {
  return httpResponse(
    { error: "Please try again later" },
    { status: 429, headers: { "Retry-After": "30" } },
  );
}

Responses are JSON. Return plain JSON or httpResponse(), not a native Response object. Status codes from 200 through 599 are supported; 204, 205, and 304 have no body. Custom headers can be Retry-After, Content-Language, or X-* headers other than the platform-managed X-Request-Id, X-Accel-*, and X-Sendfile. Response headers are limited to 8 KiB in total. Cookies, redirects, HTML, streaming, and binary responses are not supported.

A normal object with status and body keys is still ordinary JSON; only the helper creates an HTTP response envelope. Cache-Control: no-store and X-Request-Id are set by Octocom. JavaScript/TypeScript failures return a generic error and request ID; full diagnostics are available to authorized authors.

Limits and retries

These endpoints are for human-driven workflows, not high-volume APIs.

LimitDefault
Endpoint traffic10 requests/minute refill, burst capacity 5
Organization traffic30 requests/minute refill, burst capacity 10
Concurrent executions2 per endpoint, 5 per organization
Execution deadline30 seconds, including sandbox setup and waiting
Request body64 KiB
Response body256 KiB

Limits are shared across server processes. When a rate or concurrency limit is reached, the endpoint returns 429 with Retry-After; requests are not queued by Octocom. Tests share these limits. Contact Octocom if you need higher limits.

A timeout returns 504. A timeout does not prove that no action happened. Dispatched JavaScript/TypeScript or a third-party request can still finish after the HTTP caller stops waiting. Octocom does not automatically retry endpoint executions. Make state changes idempotent when duplicate calls would matter, and inspect the outcome before retrying an uncertain request. A concurrency slot with an uncertain outcome is held for up to five minutes to bound outstanding work.

Test and debug

Save the endpoint, then use Test request. You can test unsaved code in the editor; method settings come from the saved endpoint. Tests work while an endpoint is disabled.

Tests execute real JavaScript/TypeScript and may make real writes. They are not a dry run. The result shows the HTTP status, body, headers, duration, request ID, and execution failure details.

Recent requests retain metadata for 24 hours: request ID, code revision, timestamp, method, status, duration, and whether the request was a test. JavaScript/TypeScript failures additionally retain bounded, secret-redacted error details and captured console output. Request headers, request bodies, and response bodies are not stored in invocation history. Avoid logging customer data or tokens: authored output can appear in failure diagnostics.

Invocation records expire automatically from Redis and are best-effort diagnostics, not a permanent audit trail. The dashboard shows the latest 100 records. Configuration history is retained separately; inspect and restore it under Version history. Restoring a version also restores its enabled state.

Copilot and MCP

Ask Copilot to create an endpoint, implement the behavior, and test it with a sample request. Available tools:

  • list_http_endpoints and get_http_endpoint
  • create_http_endpoint, update_http_endpoint, and delete_http_endpoint
  • test_http_endpoint
  • list_http_endpoint_invocations
  • list_http_endpoint_versions and restore_http_endpoint_version

Tools are scoped to the selected organization. Creation requires a businessId from that organization. Test tools are writes because their JavaScript/TypeScript code can perform actions.

REST configuration API

The management API uses your normal Octocom X-API-Key. This is separate from invoking the generated URL, where your code defines any authentication.

MethodPathPurpose
GET/rest/v1/custom-http-endpointsList endpoint configurations; optionally filter by businessId
GET/rest/v1/custom-http-endpoints/:idGet configuration and JavaScript/TypeScript code
POST/rest/v1/custom-http-endpointsCreate an endpoint
PATCH/rest/v1/custom-http-endpoints/:idUpdate supplied fields
DELETE/rest/v1/custom-http-endpoints/:idSoft-delete an endpoint

Create with:

{
  "businessId": "YOUR_BUSINESS_UUID",
  "name": "Contact form",
  "description": "Accept a help-center contact form",
  "methods": ["POST"],
  "isActive": true,
  "code": "export async function handle(context) { return { success: true }; }"
}

Responses use a data envelope. Creation returns 201 with the generated invocation URL. List responses omit source code; use the detail route to retrieve it. The API key's organization controls which endpoints and businesses are accessible.

On this page