Flowmingo Logo

Integrations

API Integration Guide

Authenticate with Flowmingo, request API keys, and trigger async interview invitations directly from your ATS or backend workflows.

Need help integrating?

Stuck on a step or need technical support? Our team is happy to help — reach out any time and we'll get you connected.

API Key Integration

Flowmingo exposes a lightweight REST surface so you can trigger interview invitations from your ATS, CRM, or internal tooling. This section explains how to create API keys and use them to call Flowmingo's integration APIs.

1. Prerequisites

  • Workspace access: You need access to Settings -> Integrations -> API Keys in the company workspace.
  • Interview set and/or project ID: Keep the UUID you will target (com_interview_set_id and/or com_project_id).
  • CV file hosting (if sending CVs): Upload CVs to publicly accessible HTTPS storage (or signed URLs) that Flowmingo can fetch.

2. Request an API key

2.1 Open the API Keys panel

  1. Sign in at https://team.flowmingo.ai.
  2. Open your avatar menu -> Settings.
  3. Go to Integrations -> API Keys.

2.2 Create a key

  1. Click Create API Key.
  2. Provide optional Name and Description.
  3. (Optional, recommended) add scopes such as invite_candidates or create_set.
  4. Click Generate.

You will receive a one-time secret with format like fl_live_abcd12345.<secret>. Copy and store it immediately. After creation, key values are masked (for example: fl_live_abcd12345.****).

2.3 Update metadata

Use Edit on an existing key to update:

  • name
  • description
  • scopes
  • status

2.4 Rotate or revoke

Delete a key to revoke access immediately, then create a new key and update your integrations.

2.5 Security notes

Store API keys in a secret manager (AWS Secrets Manager, GCP Secret Manager, 1Password, etc.). Never embed keys in frontend code, logs, or version control.

2.6 Authenticate your requests

Send the key in the X-API-Key header:

X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj

Authorization: Bearer <key> is NOT accepted by this API. It is a common habit, and it fails with a 401 whose message is "API key is required" — which reads like the key is missing even though you sent one. If you prefer the Authorization header, the scheme must be the literal word ApiKey: Authorization: ApiKey fl_live_.... (Our MCP server at mcp.flowmingo.ai does accept Bearer; this REST API does not.)

To check a key without side effects, call the introspection endpoint — it needs no scope, so any valid key can verify itself:

curl -s -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  https://apis.flowmingo.ai/company/integration/me/v1
{
  "api_key_id": "0b0a...",
  "organization_id": 12345,
  "scopes": ["read_hiring", "read_candidates", "write_pipeline", "invite_candidates", "create_set"],
  "expires_at": null
}

A 200 proves the key is accepted and shows which organization and scopes it carries. Anything else, see section 6, Troubleshooting.

3. Create interview sets through the API

Use this endpoint to programmatically provision an interview set (interview or CV set) along with its questions, requirements, and access list.

3.1 Endpoint & environments

Environment Settings URL API
Production https://team.flowmingo.ai https://apis.flowmingo.ai/company/integration/interview/set/v1

Method: POST. Required API key scope: create_set.

3.2 Request payload

Field Type Required Notes
title string Yes Max 1024 chars. Display title for the interview set.
position string Optional Max 1024 chars. The job title / role being hired for.
set_type int Optional 1 = interview (default), 2 = CV set.
description string Optional Free-text description.
interview_duration int Optional Duration in minutes.
cfg_lingual_ids int[] Optional Languages the interview may be conducted in. 290 = English, 204 = Hindi (India); see 3.2.4 below. Omit it and English is applied.
number_of_retakes int Optional Number of allowed retakes for candidates.
priority int Optional Sort/priority weighting.
project_id UUID Optional If provided, the interview set is attached to this project.
iai_questions array Optional Interview questions (see 3.2.1).
iai_requirements array Optional Evaluation requirements (see 3.2.2).
com_accesses array Optional Recruiter/collaborator access entries (see 3.2.3).

3.2.1 iai_questions[] item

Field Type Required Notes
title string Optional Max 5000 chars.
content string Optional Max 5000 chars. The question prompt.
hint string Optional Max 2000 chars.
details string Optional Max 10000 chars. Long-form context / instructions.
question_mode string Optional One of pre_screening, interview. Defaults to interview. Mapped server-side to cfg_question_mode_id.
question_type string Optional One of text, checkbox, radio, file. Defaults to text. Mapped server-side to cfg_question_type_id.
priority int Optional Order weight.
options array Optional Choice options: { id, title, titles, content, contents, priority }.
attributes object Optional Arbitrary metadata.

3.2.2 iai_requirements[] item

Field Type Required Notes
title string Optional Max 5000 chars.
content string Optional Max 5000 chars. Requirement description.
hint string Optional Max 2000 chars.
cfg_importance_id int Optional Importance level — see below.
tal_skill_ids int[] Optional Skill IDs linked to this requirement.
priority int Optional Order weight.
attributes object Optional Arbitrary metadata.

cfg_importance_id values. These are configured IDs, not a 1-4 scale, and the lowest ID is the weakest importance. Importance sets how heavily the requirement counts toward the candidate's evaluation score. The ID selects the importance, and the importance carries the weight:

cfg_importance_id Importance Weight in the evaluation score
244 Good To Have 1x
245 Important 2x
272 Very Important 3x
273 Must Have 4x

If omitted, or if the value is not one of the four above, the requirement is stored as 244 (Good To Have).

3.2.3 com_accesses[] item

Field Type Required Notes
email string Yes Valid email, max 250 chars. Identifies the access target.
fullname string Optional Max 500 chars.
firstname string Optional Max 250 chars.
lastname string Optional Max 250 chars.
priority int Optional Order weight.
attributes object Optional Arbitrary metadata.

3.2.4 cfg_lingual_ids values

Like cfg_importance_id, these are configured IDs rather than a sequence, so the two you are most likely to need are listed here:

cfg_lingual_ids Language
290 English
204 Hindi (India)

Send them as an array of integers, e.g. [290] or [290, 204]. The array is the set of languages a candidate is allowed to conduct the interview in.

If you omit the field, English is applied for you. That default is best-effort, so send [290] explicitly if your integration depends on the language being set deterministically. CV sets (set_type: 2) have no interview, so the field is ignored for them.

Need an ID for a language that is not listed? Ask us rather than guessing — a value that is not a real configuration ID is stored as-is and then resolves to nothing.

Evaluation report language is a separate setting that this endpoint's documented contract does not cover, so do not rely on setting it here. If none is ever stored, reports come out in English. Once a language has been stored for a set it is fixed — a later attempt to change it is ignored rather than rejected, because reports already written are never regenerated.

3.3 Sample request

curl -X POST https://apis.flowmingo.ai/company/integration/interview/set/v1 \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  -d '{
    "title": "Senior Backend Engineer - Async Interview",
    "set_type": 1,
    "description": "Async interview for senior backend candidates.",
    "interview_duration": 30,
    "number_of_retakes": 1,
    "project_id": "019c5ea9-a792-7f0d-b671-4c3c1602094e",
    "iai_questions": [
      {
        "title": "System design",
        "content": "Walk us through how you would design a rate limiter.",
        "question_mode": "interview",
        "question_type": "text",
        "priority": 1
      }
    ],
    "iai_requirements": [
      {
        "title": "5+ years backend experience",
        "cfg_importance_id": 273,
        "priority": 1
      }
    ],
    "com_accesses": [
      { "email": "recruiter@example.com", "fullname": "Jane Recruiter" }
    ]
  }'

3.4 Sample response

The endpoint returns a results envelope.

Treat the response as an acknowledgement, not a confirmation. results is built from the payload you submitted rather than re-read from the saved record, so a field can appear in the response and not be stored — a cfg_importance_id outside the four valid IDs is echoed back to you unchanged and stored as 244. To confirm what actually persisted, fetch the interview set after creating it.

{
  "results": {
    "id": "019c6010-2f3a-7a91-9b70-4c1a6f57c8ab",
    "title": "Senior Backend Engineer - Async Interview",
    "set_type": 1,
    "interview_duration": 30,
    "number_of_retakes": 1,
    "com_project_id": "019c5ea9-a792-7f0d-b671-4c3c1602094e",
    "iai_questions": [
      {
        "id": "019c6010-3a01-77e2-9d2c-2d4a8b41f13b",
        "title": "System design",
        "content": "Walk us through how you would design a rate limiter.",
        "cfg_question_mode_id": 248,
        "cfg_question_type_id": 250,
        "priority": 1
      }
    ],
    "iai_requirements": [
      {
        "id": "019c6010-3b1f-7ce9-86c4-6c0aa1c3f9d2",
        "title": "5+ years backend experience",
        "cfg_importance_id": 273,
        "priority": 1
      }
    ],
    "com_accesses": [
      {
        "id": "019c6010-3c4d-71b8-9e9b-9f0d2c4b8e51",
        "email": "recruiter@example.com",
        "fullname": "Jane Recruiter"
      }
    ]
  }
}

4. Invite candidates through the API

4.1 Endpoint & environments

Environment Settings URL API
Production https://team.flowmingo.ai https://apis.flowmingo.ai/company/integration/interview/candidate/invite/v1

4.2 Request payload

Field Type Required Notes
com_interview_set_id UUID Conditionally Required if com_project_id is not provided.
com_project_id UUID Conditionally Required if com_interview_set_id is not provided.
com_job_post_id UUID Optional If omitted while com_project_id is provided, the latest job post in that project is selected.
candidates array Yes Must contain at least 1 candidate.
candidates[].ats_candidate_id UUID Optional Must be unique within a single request.
candidates[].email string Optional Required for invite creation; if missing and cv_link exists, the request queues candidate-entry CV processing instead.
candidates[].name string Optional Candidate display name.
candidates[].firstname string Optional Candidate first name override.
candidates[].lastname string Optional Candidate last name override.
candidates[].cv_link string URL Optional CV source URL for evaluation workflows.
invitation_message string (>=10 chars) Optional Custom message content.
send_invite boolean Optional (default true) When true, invitation records are created for interview-set flows.

4.3 Sample request

curl -X POST https://apis.flowmingo.ai/company/integration/interview/candidate/invite/v1 \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  -d '{
    "com_interview_set_id": "019c5ea9-a792-7f0d-b671-4c3c1602094e",
    "candidates": [
      {
        "name": "Alex Doe",
        "email": "alex@example.com",
        "cv_link": "https://storage.googleapis.com/flowmingo-demo/cv/alex.pdf"
      }
    ],
    "invitation_message": "Hi {{name}}, please complete the async interview in the next 48 hours.",
    "send_invite": true
  }'

4.4 Sample response

The endpoint returns a response envelope with per-candidate results:

{
  "results": [
    {
      "email_address": "alex@example.com",
      "cv_link": "https://storage.googleapis.com/flowmingo-demo/cv/alex.pdf",
      "invitation": {
        "id": "019c5eb3-fb50-707b-9833-0862efa4b275",
        "email": "alex@example.com",
        "status_text": "pending"
      },
      "submission": {
        "id": "019c5eb4-55ab-76fc-90ec-98930c56a7bd",
        "status_text": "need_interview"
      }
    }
  ]
}

Error details are returned per candidate in fields such as error_message, invitation_error_message, application_error_message, submission_error_message, and candidate_entry_error_message.

5. Read results through the API

These endpoints are read-only. They are how you pull scores and the AI's written evaluation into your own system, instead of sending people to Flowmingo to read a report.

5.1 What you can read

All paths below are prefixed with https://apis.flowmingo.ai/company/integration.

Endpoint Scope Returns
GET /me/v1 any valid key The key's organization and scopes (see section 2.6).
GET /hiring/submissions/v1 read_hiring A page of submissions. Use it to find a submission_id.
GET /hiring/submissions/{id}/detail/v1 read_hiring One submission, with the AI evaluation.
GET /hiring/submissions/{id}/v1 read_hiring One submission, without the AI evaluation.
GET /hiring/interview-sets/v1 read_hiring Your interview sets.
GET /hiring/job-posts/v1, GET /hiring/job-posts/{id}/v1 read_hiring Your job posts.
GET /hiring/projects/v1, GET /hiring/projects/{projectId}/stages/v1 read_hiring Projects and their pipeline stages.
GET /hiring/applications/v1 read_hiring Pipeline applications.
GET /hiring/interviews/upcoming/v1 read_hiring Invited, not yet completed.
GET /hiring/overview/v1 read_hiring Aggregate counts for a funnel view.
GET /hiring/candidates/v1, GET /hiring/candidates/{id}/v1 read_candidates Candidate name, email and CV link. The single-candidate route also returns phone and thumb_cv_link.
GET /events/v1 read_hiring Your webhook events, cursor-paginated. Poll these if you cannot host an endpoint.

Every read is scoped to the organization that owns the key — no endpoint can return another organization's data. The id-addressed routes (job-posts/{id}, submissions/{id}, submissions/{id}/detail, candidates/{id}) answer 404 for an id you do not own; the list routes simply return no matching rows.

Candidate names and emails require read_candidates. read_hiring returns ids, scores and evaluations. Without read_candidates, the candidate_name, firstname, lastname and email fields are omitted from the applications, submissions and submission-detail responses. GET /me/v1 shows what your key holds.

5.2 Find a submission

curl -s -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  'https://apis.flowmingo.ai/company/integration/hiring/submissions/v1?com_interview_set_id=019bcb66-2d6e-795a-9770-148355e51c51&limit=20'
Query param Type Notes
com_interview_set_id uuid Only submissions for this interview set.
tal_candidate_id uuid Only submissions for this candidate.
sort_by string created_at (default) or overall_score. Rows with no score always sort last, whichever direction you ask for.
order string asc or desc (default desc).
completed_within_days integer Completed in the last N days (max 3650). Ignored if you also send completed_from.
completed_from, completed_to ISO date Completion window. A bare YYYY-MM-DD in completed_to covers that whole day; a full timestamp is used as given.
with_project boolean Send true or 1. Adds com_project_id to each row — it is null for a set that maps to no single project.
page, limit integer page defaults to 1 (max 100000), limit to 20 (max 100). Both must be positive: limit=0 is a 400, not "use the default".

The response is { "data": [ ... ], "total": n, "page": 1, "limit": 20 }. Each row carries id (the submission id), status, com_interview_set_id, tal_candidate_id, assessment_type, assessment_name, overall_score, score_status, submission_at and created_at — plus candidate_name, firstname, lastname and email when your key carries read_candidates. score_percent appears only on a released skill-test row that has a score; test for the key rather than for null.

5.3 Read the evaluation

curl -s -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  'https://apis.flowmingo.ai/company/integration/hiring/submissions/{submission_id}/detail/v1'
{
  "id": "59065d06-a013-44c2-97d2-88e9d6b3c858",
  "submission_id": "59065d06-a013-44c2-97d2-88e9d6b3c858",
  "status": 1,
  "com_interview_set_id": "adf40c5c-ba95-4aa4-8804-1b309014df59",
  "tal_candidate_id": "019bcb66-66d9-781e-96cc-e4a2b74c7fce",
  "assessment_type": "ai_interview",
  "assessment_name": "AI Engineer - AI Interview",
  "candidate_name": "Alex Kim",
  "firstname": "Alex",
  "lastname": "Kim",
  "email": "alex@example.com",
  "overall_score": 7.2,
  "score_status": "scored",
  "submission_at": "2026-09-10T12:00:49.000Z",
  "created_at": "2026-09-10T11:14:02.000Z",
  "evaluation": {
    "summary": "A strong applied engineer who has shipped retrieval systems end to end...",
    "overall_rating": 7.2,
    "strengths": ["Ships production RAG pipelines", "..."],
    "gaps": ["Limited exposure to evaluation tooling", "..."],
    "recommendations": ["Probe observability practices in a follow-up", "..."],
    "competencies": [
      { "name": "Applied AI/ML Engineering", "rating": 9 },
      { "name": "Conversational AI", "rating": 3 }
    ]
  },
  "evaluation_cv": { "summary": "...", "overall_rating": 7.9 }
}
  • overall_score is out of 10, and so is every competencies[].rating. It is null when there is no usable number — score_status says which: scored, cannot_evaluate (the AI ran and could not rate the attempt) or not_scored (no score yet). A cannot_evaluate is not a zero.
  • status is a number: 0 inactive, 1 active (complete), 2 pending, 3 archived, 4 incomplete, 5 needs interview, 6 retaking.
  • assessment_type is one of ai_interview, cv_evaluation, skill_test, showcase, unknown. A skill test also carries score_percent (the real percentage), because overall_score is normalised onto the same 0-10 scale as everything else — but only when it has a score and the report is released; otherwise the key is absent.
  • evaluation holds the AI evaluation for the submission — the interview evaluation on an interview set, and the CV evaluation on a CV set (assessment_type: "cv_evaluation"). evaluation_cv is the separate CV evaluation attached to an interview set. Either can be null.
  • Inside either object, a key you do not see is absent, not null — competencies is omitted entirely when there are no per-criterion rows, so test if (evaluation?.competencies) rather than comparing with []. Both objects may also carry rating_status: "cannot_evaluate", meaning the AI ran but could not rate the attempt.
  • competencies[].name is the title of each iai_requirements[] item you sent. Name them whatever you like; they come back under those names. A requirement you sent with an empty title is left out of the evaluation altogether.

5.4 Ask for the full detail: ?include=

Two extras are opt-in. Combine them with a comma. rubric is opt-in because it costs an extra column read most callers never need; justifications is opt-in because this same response feeds our in-product assistant, and written reasoning about a candidate should be something you ask for.

Value Adds
justifications The AI's written reasoning for each criterion, as competencies[].justification.
rubric Up to 13 communication and cognitive dimensions, each with a score out of 5 and a written rationale. A dimension the evaluation did not produce is left out of the array.
curl -s -H 'X-API-Key: fl_live_abcd12345.n8G3zPNw9gWkK1Kj' \
  'https://apis.flowmingo.ai/company/integration/hiring/submissions/{submission_id}/detail/v1?include=justifications,rubric'
{
  "evaluation": {
    "competencies": [
      {
        "name": "Applied AI/ML Engineering",
        "rating": 9,
        "justification": "Described building and deploying two retrieval pipelines, including how they chunked and evaluated them."
      }
    ]
  },
  "rubric": [
    { "key": "grammar", "label": "Grammar", "group": "communication", "score": 4, "score_max": 5, "rationale": "..." },
    { "key": "logical_reasoning", "label": "Logical Reasoning", "group": "cognitive", "score": 3.5, "score_max": 5, "rationale": "..." },
    { "key": "clarity", "label": "Clarity", "group": "cognitive", "score": null, "score_max": 5, "score_status": "cannot_evaluate", "rationale": "Too little sustained speech to judge." }
  ]
}

Two scales in one response. Your criteria (competencies[].rating) and overall_score are out of 10. The rubric is out of 5 — every rubric row repeats score_max so the two cannot be confused.

The rubric's group is communication (Grammar, Comprehension, Fluency, Vocabulary, Coherence) or cognitive (Logical Reasoning, Critical Thinking, Problem Solving, Big-picture thinking, Intellectual Self-Awareness, Insightfulness, Clarity, Decision Making). It is the same rubric shown in the report inside Flowmingo.

score is null whenever the stored value is not a number between 0 and 5. When the AI ran and explicitly could not rate a dimension, that row also carries score_status: "cannot_evaluate" — so a null score with no score_status simply means no usable rating was recorded. rationale can be null independently of the score. rubric itself is null when the submission has none; it is produced for AI interviews.

An unrecognised include value returns 400 rather than being ignored, so a typo cannot look like "the feature returned nothing".

5.5 When a score or evaluation is missing

A candidate may be given a window to improve their answers after finishing. While that window is open the result is deliberately withheld, so you never store a score that is about to change: status reads 6 (retaking), score_status reads "not_scored" even though a score exists, and overall_score, submission_at, evaluation and rubric come back null. status: 6 is what distinguishes a withheld result from one that was never scored.

This is temporary and resolves itself. The interview.evaluation.update webhook is held back for the same reason and re-sent by a job that runs every 10 minutes, so it arrives shortly after the window closes. Read the detail endpoint when that webhook arrives rather than polling straight after an interview ends. See the webhook guide.

6. Troubleshooting

401 and 403 mean different things, and the message usually tells you which problem you have. Checks run in order — key present, well-formed, recognised, unexpired, correctly scoped — and the first failure is the one reported, so an expired key reports expiry even if something else is also wrong:

Status Message What it means
401 API key is required No key reached us. The header name is wrong, or you sent Authorization: Bearer — see section 2.6. Generating a new key will not help.
401 Invalid API key format The key is malformed: it must be the full prefix.secret value, including the ..
401 Invalid API key The key is not recognised, or it was deleted or deactivated. A masked value copied from the key list (fl_live_abcd12345.****) also lands here — it is well-formed, but the secret is not the real one.
403 API key expired The key passed its expiry date.
403 API key missing required scope: <scope> The key is valid but lacks that scope (create_set to create sets, invite_candidates to invite, read_hiring to read results, read_candidates for candidate names and emails).

There is no separate "enable API access" setting on an account: a key that exists, is active, has not expired and carries the right scope works.

  • 404 project/interview set: The UUID is invalid for your organization or the record is deleted.
  • Validation errors (invite): Ensure candidates is non-empty and each candidate has enough data for your desired flow (invite vs CV-entry queue).
  • Validation errors (set): title is required. question_mode and question_type are optional — omit them and you get interview / text — but if you DO send one it must be a valid value (pre_screening | interview, and text | checkbox | radio | file). Also check max-length limits on string fields, and that project_id (if sent) is a valid UUID owned by your organization.
  • Evaluation criteria look wrong or missing: check cfg_importance_id against the four IDs in 3.2.2 — a value outside that set is stored as 244 (Good To Have) rather than rejected.
  • Duplicate ATS IDs in one payload: Ensure candidates[].ats_candidate_id values are unique per request.