Use BA Copilot with the Process Maps API

Generate and refine BPMN process maps programmatically with the BA Copilot REST API.

Last updated · 4 min read

The Process Maps API lets you generate and refine BPMN process maps programmatically. Send a text prompt to a single endpoint and get back BPMN 2.0 XML you can render, store, or feed into your own tools.

Try the public mock demo at ba-copilot.com/api-access first to see what the request and response look like with no signup required.

Enable API access

  1. Sign in to BA Copilot.
  2. Open Settings → API.
  3. Enable the Process Maps API Labs feature. (It is currently a Labs feature, so the contract may evolve before general availability.)

Create an API key

  1. From the same Settings → API page, click Create key.
  2. Give it a memorable name (for example, "production" or "staging-tests").
  3. The full key is shown once. Copy it and store it securely — we only keep a hash, so we cannot recover it for you. Keys are prefixed bac_sk_.

Authenticate every request with a bearer token:

Authorization: Bearer bac_sk_...

The Test Console

Settings → API also includes a built-in Test Console. You can:

  • Choose Initial or Refinement mode.
  • Edit the JSON request body inline.
  • Send a mock request (instant, no API key, no quota used) or a live request (uses 1 generation from your quota).
  • Inspect the response as a rendered BPMN preview, raw JSON, or BPMN XML.
  • Promote any returned diagram into a real Process Map in your workspace.

Two modes: initial and refinement

Initial — create a new process map

Send a text prompt and the API returns three distinct BPMN options so you (or your end user) can pick the best starting point.

POST /api/v1/process-maps/generations Authorization: Bearer bac_sk_... Content-Type: application/json { "mode": "initial", "prompt": "Map the customer support ticket triage process from intake to resolution.", "language": "english" }

Successful response (200 OK):

{ "id": "33333333-3333-4333-8333-333333333333", "status": "succeeded", "mode": "initial", "request_id": "req_01HZX2KQ8Q3W4Y5Z6A7B8C9D0E", "options": [ { "option_number": 1, "versions": [{ "version_number": 1, "bpmn_xml": "..." }] }, { "option_number": 2, "versions": [{ "version_number": 1, "bpmn_xml": "..." }] }, { "option_number": 3, "versions": [{ "version_number": 1, "bpmn_xml": "..." }] } ] }

Refinement — evolve an existing process map

Send a follow-up prompt to refine an existing diagram. The API returns one updated result. Reference a stored generation by id (recommended), or pass inline BPMN XML in source.bpmn_xml.

POST /api/v1/process-maps/generations Authorization: Bearer bac_sk_... Content-Type: application/json { "mode": "refinement", "prompt": "Add an escalation path for high-severity tickets.", "source": { "generation_id": "33333333-3333-4333-8333-333333333333", "option_number": 2, "version_number": 1 } }

Successful response:

{ "id": "44444444-4444-4444-8444-444444444444", "status": "succeeded", "mode": "refinement", "request_id": "req_01HZX2KQ8Q3W4Y5Z6A7B8C9D0E", "result": { "option_number": 1, "version_number": 2, "bpmn_xml": "...", "source": { "generation_id": "33333333-3333-4333-8333-333333333333", "option_number": 2, "version_number": 1 } } }

Sync vs async

By default the request waits for completion (?wait=true) and returns the BPMN inline. If a generation runs longer than the request window, you get a 202 Accepted with status: "running" and a links.self URL to poll.

Set ?wait=false to start the job in the background and immediately receive a 202 with the self link — useful when you do not want to hold a long-lived HTTP connection.

{ "id": "22222222-2222-4222-8222-222222222222", "status": "running", "request_id": "req_...", "links": { "self": "/api/v1/process-maps/generations/22222222-2222-4222-8222-222222222222" } }

Background jobs are best-effort. If a generation does not finish within the time limit it transitions to timed_out. The full timeout is 10 minutes.

Idempotency

Pass an Idempotency-Key header (any string up to 256 characters, typically a UUID) to make retries safe. If you replay a request with the same key and body within 30 days, the API returns the original response without starting a new generation.

Idempotency-Key: 9d4e0a36-8a16-4b7b-9c2c-8b1b0e9a7c54

List, retrieve, and delete generations

Generations are stored against your account so you can fetch them later.

GET /api/v1/process-maps/generations # cursor-paginated list GET /api/v1/process-maps/generations/{id} # retrieve one

To delete a stored generation, use the dashboard: open Settings → API → History, select the item, and click Delete stored result.

Limits and quotas

  • Prompts are capped at 50,000 characters.
  • Generations time out after 10 minutes (status transitions to timed_out).
  • Trial users get a 50-generation API quota; subscribers consume their plan's generation quota.
  • Idempotency keys are retained for 30 days.

Error format

All non-2xx responses share a consistent error envelope:

{ "error": { "code": "invalid_request", "message": "prompt must be 50,000 characters or fewer.", "request_id": "req_...", "details": { "field": "prompt" } } }

Always log request_id — it is the fastest way for support to trace what happened.

OpenAPI spec

The full machine-readable contract is at https://ba-copilot.com/api/v1/openapi.json. Use it to generate clients, run mock servers, or import into Postman.

Promoting API generations to Process Maps

Generations created through the API show up in Settings → API → History. From there you can promote any returned option/version into a real Process Map in any of your workspaces — useful for testing prompts via the API and then continuing to refine them with the chat UI.

Chaining refinements

Each call to POST /api/v1/process-maps/generations creates a new generation with a brand-new id. Refinements are no exception — a refinement is not "version 2 of the original", it is a new generation that happens to reference the source generation in its source.generation_id field.

That means in every refinement response:

  • result.option_number is always 1
  • result.version_number is always 1

Why? Each generation is its own root. The API deliberately does not maintain a global "this is the 4th refinement" counter — that would force the API to make domain decisions you would usually want to make yourself (does branching reset the counter? does discarding a refinement renumber the chain?).

If you want to render a "draft 1 → draft 2 → draft 3" timeline in your product, walk the source.generation_id links yourself and assign your own ordinal. A typical client-side helper:

// Walk source.generation_id back to the root and number the chain.    async function buildChain(generationId, depth = 0) {      const gen = await fetch(`/api/v1/process-maps/generations/${generationId}`)        .then((res) => res.json());      const sourceId = gen.result?.source?.generation_id;      if (!sourceId) return [{ id: gen.id, label: `v${depth + 1}`, gen }];      const chain = await buildChain(sourceId, depth + 1);      return [...chain, { id: gen.id, label: `v${depth + 1}`, gen }];    }

Two refinements off the same source naturally form a fork — both will return (1, 1) in their own generations. If your product needs to handle forks, treat the chain as a tree, not a list.

Why initial generations also use version_number: 1

For symmetry. option_number ranges 1–3 for initial generations and is always 1 for refinements. version_number is always 1. The field encodes "which option/version within this single generation" — not evolution depth. Keeping it constant keeps the semantics clean.

Need help?

This is a Labs feature, so the surface area is still evolving.

Was this guide helpful?

More in Creating process maps