Documentation version: 2026-10-23.6
Canonical: https://docs.creator.gg/guides/app-integrations.md

# Integrate your app with Creator Platform

Your existing coding agent can build the integration using these instructions and the official runtime kit. The app then calls Creator Platform directly, without a running agent or an AI model for each request. The same supported contacts, audiences, email, social, media, intelligence and growth tools are available through the authenticated MCP interface. Discover actual tools and inspect their schemas; workspace access and provider capabilities still apply. Tools returning an account-screen handoff do not become programmable through the client.

## 1. Verify capabilities and obtain the runtime kit

In the coding agent, discover tools and call workspace_status. Confirm the intended business and enabled modules. Read tools/contacts_upsert and guides/contacts for CRM work, or the relevant workflow and tool pages for another capability. Free intelligence-only connections need Creator Platform activation for contacts and other connected execution.

Fetch https://agents.creator.gg/downloads/agent-kit/v1/manifest.json over HTTPS. Require version 1, release 1.1.16 or later and endpoint https://mcp.creator.gg/mcp. Fetch the required artifacts from that same HTTPS directory and verify each SHA-256 against its manifest entry. Reject unexpected origins, unsafe paths and missing/mismatched checksums. HTTPS establishes the publisher; hashes detect mixed or corrupted downloads.

Runtime artifacts:
- creator-client.mjs and creator-client.d.mts: portable server-side client and TypeScript declarations.
- creator-file-store.mjs and creator-file-store.d.mts: private persistent-file storage for single-host Node.js/Bun backends.
- app-connect.mjs: independent app authorization, connection check and revocation.
- examples/form-handler.mjs and examples/form-handler.d.mts: a reusable same-origin JSON form endpoint.

Use existing Node.js 22+ or Bun. Copy the verified client and required storage adapter into the customer's app server code. The files contain no workspace credentials. Preserve customized installed skills and unrelated app configuration.

## 2. Authorize the deployed app

Run the official helper in a private server-side environment where the app connection can be saved:

```sh
node app-connect.mjs --name "My website lead form" --output /absolute/private/creator-app.json
```

It registers this app as its own OAuth client with S256 PKCE and refresh support. Give the person ONLY the printed https://agents.creator.gg/oauth/pair link and short code. They sign in and approve this named app for their business. Pairing works when their browser is on a different computer. Keep the helper running; it verifies the callback issuer/state and the app's actual workspace access, then writes credentials directly to the private file. It never reads the coding agent's credential store and refuses to overwrite an existing output file. Setup performs only a workspace read, not a contact or marketing mutation.

The existing coding-agent connection remains connected. The app appears as a separately named connection in the same dashboard and can be revoked independently. The existing consent grants workspace tool access; this release does not claim contact-only OAuth scopes. Keep that app credential server-side and expose only the specific operations the app needs. Current human workspace access, revocation and the existing 90-day inactivity policy still apply.

For an existing app connection, use the helper's --check /absolute/private/creator-app.json. Reconnect into a new private file if access is revoked or rotation became uncertain, then replace the deployment secret deliberately. Revoke only this app through the dashboard or --revoke /absolute/private/creator-app.json. Never copy a coding agent's token into the app, use internal operator credentials, request a provider API key or construct REST routes from tool names.

## 3. Choose durable runtime storage

For a persistent single-host Node.js/Bun backend, keep the connection file outside the public app tree, restrict the directory to the service user and set CREATOR_CONNECTION_FILE to its absolute path. The helper writes owner-only file permissions on Unix; restrict Windows ACLs to the service account. Add the private path to the app's ignore rules. The file-store adapter serializes processes using a sibling lock file, writes tokens atomically and never steals a stale lock. After a crashed process, inspect ownership before removing only that abandoned app lock.

For serverless or multiple replicas, use encrypted durable private storage and implement CreatorConnectionStore.run. It MUST acquire a distributed exclusive lock for this connection, read the latest connection, await the supplied operation and commit each persist(next) durably before returning. Hold the lock until the operation finishes. Do not hold a database transaction across remote HTTP; use a renewable application-level lease with fencing, with persist rejecting a lost lease. No other instance may refresh the same credential concurrently. Use the app's existing durable lock/secret infrastructure; local temporary disk, a static environment variable and process-only mutexes cannot persist rotating refresh tokens across replicas. The pure client has no Node filesystem dependency.

The runtime client refreshes before expiry. It durably marks an exchange pending before submitting the rotating refresh token, then saves the replacement before executing the tool. A crash, storage failure or uncertain exchange requires reconnecting that app, rather than replaying the old token and revoking its grant. Server-to-server calls need no browser Origin header. The public endpoint remains https://mcp.creator.gg/mcp; never expose runtime credentials in browser requests.

## 4. Form submissions into the CRM

Adapt the following into the existing app's server route (for example, app/api/lead/route.ts in Next.js). Download the verified artifacts above; the example import paths assume they are stored in server/creator and server/creator/examples. Reuse the application's existing rate limiting, spam protection and consent records.

```js
import { createCreatorClient } from '../../../server/creator/creator-client.mjs';
import { createFileConnectionStore } from '../../../server/creator/creator-file-store.mjs';
import { createCreatorFormHandler } from '../../../server/creator/examples/form-handler.mjs';

export const runtime = 'nodejs';
const connectionFile = process.env.CREATOR_CONNECTION_FILE;
if (!connectionFile) throw new Error('Missing private Creator connection path.');
const creator = createCreatorClient({
  store: createFileConnectionStore(connectionFile)
});
export const POST = createCreatorFormHandler({
  client: creator,
  origin: 'https://your-app.example',
  source: 'Website contact form'
});
```

The reusable handler requires an exact matching Origin, JSON input, a bounded body, a UUIDv4 requestId, a valid email and consent: true. firstName is optional. It rejects extra client fields and keeps source fixed in trusted server code. Its optional authorize(request) callback lets the app enforce existing signed-in access or submission policies before reading the JSON body. It calls contacts_upsert with the stable form:UUID request ID. Account deduplication and existing tags/DND/opt-outs are preserved. Saving a contact does not imply marketing subscription, email delivery or an automation.

Browser example inside the customer's existing form submit handler:

```js
// Allocate once per intended submission. Preserve this ID and payload on retry.
const submission = {
  requestId: crypto.randomUUID(),
  email: form.elements.email.value,
  firstName: form.elements.firstName.value,
  consent: form.elements.consent.checked
};
const response = await fetch('/api/lead', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(submission)
});
const receipt = await response.json();
if (response.ok && receipt.status === 'saved') {
  // Show the app's success state only here.
} else if (receipt.status === 'needs_reconciliation') {
  // Retain submission and receipt. Check the CRM before another attempt.
} else {
  // Retain submission and show the app's appropriate failure state.
}
```

Never create a new requestId merely to retry the same form submission. The backend's mutation receipt detects duplicate requests and mismatched reuse. A timeout is not proof of failure. The handler returns saved only for completed, needs_reconciliation for unknown/processing outcomes, and no CRM record content to the browser.

For phone, address or custom-field forms, adapt the mapping to the exact contacts_upsert schema and discover configured fields with contacts_fields_list. The supplied minimal handler intentionally accepts email and firstName only; update its validation when extending it. Keep tag names and field IDs in trusted server configuration. Add tags with contacts_tags_add using the returned contact ID and a distinct stable requestId. On a deduplicated retry the result can contain data.references instead of the original record; resolve the contact reference and read contacts_get before proceeding. Do not replace existing tags or clear suppression.

## 5. Use the rest of the supported system

Call await creator.listTools() for the complete current schemas, following all catalogue pages automatically. Call await creator.call('TOOL_NAME', arguments) for a supported operation, with a stable 8-128-character requestId for each mutation. For example, contacts_search reads contacts, audiences_list reads audiences, email_templates_create saves templates, email_campaigns_create prepares a draft and social_posts_create prepares the specified post state. Read each exact contract before choosing arguments or effects. App code can use the same docs tools and shared business intelligence.

The client returns the structured status/message/data result and understands JSON or SSE MCP responses. It validates response IDs, bounds response size, pins the official resource/issuer and rejects redirects. It never automatically retries tool calls, even on 401 or a timeout. Inspect completed, draft, scheduled, processing, failed and unknown separately. Installing the integration grants no new permission to send campaigns, publish posts or run recurring jobs; implement only the user's requested behavior. No arbitrary provider proxy, unsupported private endpoint or separate CRM is added.

Other server languages can use the same OAuth and MCP interfaces. The published client is the maintained Node.js/Bun and fetch-compatible reference, not a claim of SDK support for every language. Reuse a compatible OAuth/MCP implementation and the exact tool contracts; preserve independent app credentials, durable refresh serialization and outcome handling.

## 6. Acceptance and recovery

Verify the app's own workspace_status after deployment. With the person's authorization, submit one clearly marked test through the actual form and read contacts_search/contacts_get to verify its fields, source and existing preferences. Repeat the same submission ID and confirm no duplicate operation/contact. Verify any requested tags separately. This test must run with the app's connection, not the coding agent's credentials or mocked responses. Clean up only the test-owned record/connection if authorized and no longer needed.

Report client installed, app authorized, app deployed and fresh CRM acceptance separately. If the app needs human consent or a private deployment secret, complete the code and present that concrete connection step. Missing module access uses the returned setup link. Revoked access requires reconnecting only this app. An uncertain write retains its receipt for reconciliation. A native-screen handoff remains a handoff, and a successful build or SDK fixture is not a live customer submission.
