customer-requests

Institute Requests

An Institflow account requesting a new institute through the customer portal, and the platform owner's console review queue (approve/refuse). Cloud/control-plane only: answers 404 on a self-hosted install.

2 endpoints

POST /api/v1/portal/requests

Request a new institute. One pending request per account at a time (409 otherwise). Mails every platform owner.

Requires authenticationScopeNo additional permission

Request body

NameTypeConstraints
instituteNamerequired
string1–200 chars
slugrequired
string3–42 chars
countryrequired
string—
sizeBandrequired
enum: "small" | "medium" | "large" | "xlarge"—
phone
string—
termsVersionrequired
enum: "2026-09-23"—

Example

json
{
  "instituteName": "string",
  "slug": "string",
  "country": "string",
  "sizeBand": "small",
  "phone": "+15551234567",
  "termsVersion": "2026-09-23"
}

curl example

curl
curl -X POST "https://your-institute.example/api/v1/portal/requests" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "instituteName": "string",
    "slug": "string",
    "country": "string",
    "sizeBand": "small",
    "phone": "+15551234567",
    "termsVersion": "2026-09-23"
  }'

Responses

201The newly submitted request, pending review.
NameTypeConstraints
idrequired
string (uuid)—
instituteNamerequired
string—
slugrequired
string—
countryrequired
string—
sizeBandrequired
enum: "small" | "medium" | "large" | "xlarge"—
phonerequired
string | null—
statusrequired
enum: "pending" | "approved" | "refused"—
refusalReasonrequired
string | null—
tenantIdrequired
string (uuid) | null—
createdAtrequired
string (date-time)—
updatedAtrequired
string (date-time)—
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "instituteName": "string",
  "slug": "string",
  "country": "string",
  "sizeBand": "small",
  "phone": "+15551234567",
  "status": "pending",
  "refusalReason": "string",
  "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z"
}
400The request could not be read at all — unparseable body, unusable content type, oversized payload (`MALFORMED_REQUEST`). Never a schema failure: those are 422.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

401Missing, expired or invalid credentials (`UNAUTHORIZED`, `TOKEN_INVALID`, `SESSION_REVOKED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

403Authenticated, but not allowed (`FORBIDDEN`, `FEATURE_DISABLED`, `QUOTA_EXCEEDED`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

404No such resource, or it is not visible to this tenant (`NOT_FOUND`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

409Conflicts with current state (`CONFLICT`, `VERSION_CONFLICT`, `IDEMPOTENCY_KEY_REUSED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

422The request was read but its content is not acceptable: body/query/path/header failed schema validation (`VALIDATION_ERROR`, with `details.issues`), or a domain rule rejected a well-formed value (`VIDEO_URL_INVALID`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

429Rate limit exceeded — see the `RateLimit-*` and `Retry-After` headers (`RATE_LIMITED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

500Unexpected server error (`INTERNAL_ERROR`). Never carries a stack trace or SQL.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

GET /api/v1/portal/requests/mine

This account’s own institute requests, newest first.

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/portal/requests/mine" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The account’s requests.
json
[
  {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "instituteName": "string",
    "slug": "string",
    "country": "string",
    "sizeBand": "small",
    "phone": "+15551234567",
    "status": "pending",
    "refusalReason": "string",
    "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
    "createdAt": "2026-03-02T09:00:00.000Z",
    "updatedAt": "2026-03-02T09:00:00.000Z"
  }
]
400The request could not be read at all — unparseable body, unusable content type, oversized payload (`MALFORMED_REQUEST`). Never a schema failure: those are 422.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

401Missing, expired or invalid credentials (`UNAUTHORIZED`, `TOKEN_INVALID`, `SESSION_REVOKED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

403Authenticated, but not allowed (`FORBIDDEN`, `FEATURE_DISABLED`, `QUOTA_EXCEEDED`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

404No such resource, or it is not visible to this tenant (`NOT_FOUND`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

409Conflicts with current state (`CONFLICT`, `VERSION_CONFLICT`, `IDEMPOTENCY_KEY_REUSED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

422The request was read but its content is not acceptable: body/query/path/header failed schema validation (`VALIDATION_ERROR`, with `details.issues`), or a domain rule rejected a well-formed value (`VIDEO_URL_INVALID`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

429Rate limit exceeded — see the `RateLimit-*` and `Retry-After` headers (`RATE_LIMITED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

500Unexpected server error (`INTERNAL_ERROR`). Never carries a stack trace or SQL.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.