API REFERENCE
Check an application proposal
On this page
/api/applications/registration/validatePending coordinated API and documentation release. Checks an authenticated workspace’s proposed application name, explicit environment, origins and return URLs. This is a preflight, not registration or activation. After authentication, the validator does not persist an application, verify domain ownership, issue application credentials, edit provider callbacks, create fan sessions, allocate quotas or authorize spending. Normal authentication can separately provision an account and send its welcome email. A matching return URL only means it belongs to a caller-proposed origin; it does not prove domain ownership.
HTTP and standard MCP validate_application_registration use the same domain validator. Delegated OAuth excludes this tool; mcp:tools does not enable it. Discover availability in the connected host.
The workspace and proposed billing owner are derived from authenticated account/authorized organization, never caller ownership overrides. Passing preflight returns persisted:false and origins_verified:false with no application ID or token. Address limits are request validation limits, not usage allowances.
Authentication
x-api-key in header
bearerAuth bearer
Request
curl --request POST \
--url 'https://api.recoupable.dev/api/applications/registration/validate' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}'Try it
Fill in the fields, send the request from your browser, and read the live response. The curl below updates as you type.
Kept in this browser tab only and cleared when it closes.
curl --request POST \
--url 'https://recoup-api.vercel.app/api/applications/registration/validate' \
--header 'Content-Type: application/json' \
--data '{
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}'Request body required
application/json
namestringrequiredWhitespace is trimmed before requiring 1–120 characters. The response returns the trimmed name.
minLength: 1
organization_idstringOptional selected workspace, allowed only for the authenticated account or an organization it may access. Omit for the authenticated account. Caller-supplied account_id and billing_owner_id are rejected.
format: uuid
environmentstring · enumrequiredRequired; this proposal checks one environment. This does not create environment resources or allowances.
Values: "development", "production"
allowed_originsarray<string>requiredDistinct canonical exact origins, including the scheme and any non-default port. No wildcard, path, trailing slash, credentials, query or fragment. HTTPS is required; HTTP localhost, 127.0.0.1 and [::1] are accepted only in development. Those three hostnames are rejected in production. A proposed origin does not prove domain ownership.
minItems: 1 · maxItems: 32
Item properties for allowed_origins
string
return_urlsarray<string>requiredDistinct exact canonical URLs whose origin matches one of allowed_origins. Credentials and fragments are rejected. Include the URL parser’s trailing slash for a bare host. Query strings are retained literally, not used as patterns. Matching a proposed origin does not verify ownership or activate callbacks.
minItems: 1 · maxItems: 32
Item properties for return_urls
string
{
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}Responses
200Proposal accepted by the validator. No application was registered and no domain was verified.+
Cache-Controlresponse headerPreflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.
application/json
statusstringrequiredpersistedbooleanrequiredThe preflight did not persist an application or registration.
origins_verifiedbooleanrequiredNo domain-ownership proof was checked.
workspace_idstringrequiredWorkspace derived from authentication and the authorized optional organization selection.
format: uuid
billing_owner_idstringrequiredSame proposed owner as workspace_id. Attribution only: no subscription, quota, top-up or spending authority is granted.
format: uuid
namestringrequiredminLength: 1 · maxLength: 120
environmentstring · enumrequiredRequired; this proposal checks one environment. This does not create environment resources or allowances.
Values: "development", "production"
allowed_originsarray<string>requiredDistinct canonical exact origins, including the scheme and any non-default port. No wildcard, path, trailing slash, credentials, query or fragment. HTTPS is required; HTTP localhost, 127.0.0.1 and [::1] are accepted only in development. Those three hostnames are rejected in production. A proposed origin does not prove domain ownership.
minItems: 1 · maxItems: 32
Item properties for allowed_origins
string
return_urlsarray<string>requiredDistinct exact canonical URLs whose origin matches one of allowed_origins. Credentials and fragments are rejected. Include the URL parser’s trailing slash for a bare host. Query strings are retained literally, not used as patterns. Matching a proposed origin does not verify ownership or activate callbacks.
minItems: 1 · maxItems: 32
Item properties for return_urls
string
{
"status": "validated",
"persisted": false,
"origins_verified": false,
"workspace_id": "11111111-1111-4111-8111-111111111111",
"billing_owner_id": "11111111-1111-4111-8111-111111111111",
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}400Invalid body, unknown field, invalid exact origin or return URL. Semantic URL restrictions in the field descriptions are checked by the shared validator in addition to the JSON shape.+
Cache-Controlresponse headerPreflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.
application/json
statusstringrequirederrorstringrequired{
"status": "error",
"error": "Invalid application registration input"
}401Authentication runs before proposal parsing. Provide exactly one of x-api-key or Authorization: Bearer. Existing authentication failures use either error or message; read the field present.+
application/json
anyOf · ApplicationRegistrationError 1
statusstringrequirederrorstringrequiredanyOf · AuthenticationMessageError 2
statusstringrequiredmessagestringrequired{
"status": "error",
"error": "Exactly one of x-api-key or Authorization must be provided"
}{
"status": "error",
"message": "Unauthorized"
}403The authenticated account cannot select the requested workspace.+
Cache-Controlresponse headerPreflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.
application/json
statusstringrequirederrorstringrequired{
"status": "error",
"error": "Workspace not available"
}503The preflight could not complete safely. Infrastructure details are not returned.+
Cache-Controlresponse headerPreflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.
application/json
statusstringrequirederrorstringrequired{
"status": "error",
"error": "Could not validate application registration"
}Full specification
Download the OpenAPI file for complete schemas, constraints, and examples.
Download applications.jsonView operation source
{
"operationId": "validateApplicationRegistration",
"summary": "Check an application registration proposal",
"x-recoup-availability": "pending",
"description": "Pending coordinated API and documentation release. Checks an authenticated workspace’s proposed application name, explicit environment, origins and return URLs. This is a preflight, not registration or activation. After authentication, the validator does not persist an application, verify domain ownership, issue application credentials, edit provider callbacks, create fan sessions, allocate quotas or authorize spending. Normal authentication can separately provision an account and send its welcome email. A matching return URL only means it belongs to a caller-proposed origin; it does not prove domain ownership.\n\nHTTP and standard MCP validate_application_registration use the same domain validator. Delegated OAuth excludes this tool; mcp:tools does not enable it. Discover availability in the connected host.\n\nThe workspace and proposed billing owner are derived from authenticated account/authorized organization, never caller ownership overrides. Passing preflight returns persisted:false and origins_verified:false with no application ID or token. Address limits are request validation limits, not usage allowances.",
"security": [
{
"apiKeyAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationRegistrationProposal"
},
"example": {
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}
}
}
},
"responses": {
"200": {
"description": "Proposal accepted by the validator. No application was registered and no domain was verified.",
"headers": {
"Cache-Control": {
"description": "Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.",
"schema": {
"type": "string",
"const": "private, no-store"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationRegistrationPreflight"
},
"example": {
"status": "validated",
"persisted": false,
"origins_verified": false,
"workspace_id": "11111111-1111-4111-8111-111111111111",
"billing_owner_id": "11111111-1111-4111-8111-111111111111",
"name": "Release companion",
"environment": "production",
"allowed_origins": [
"https://music.example"
],
"return_urls": [
"https://music.example/listen?connected=spotify"
]
}
}
}
},
"400": {
"description": "Invalid body, unknown field, invalid exact origin or return URL. Semantic URL restrictions in the field descriptions are checked by the shared validator in addition to the JSON shape.",
"headers": {
"Cache-Control": {
"description": "Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.",
"schema": {
"type": "string",
"const": "private, no-store"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationRegistrationError"
},
"example": {
"status": "error",
"error": "Invalid application registration input"
}
}
}
},
"401": {
"description": "Authentication runs before proposal parsing. Provide exactly one of x-api-key or Authorization: Bearer. Existing authentication failures use either error or message; read the field present.",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/ApplicationRegistrationError"
},
{
"$ref": "#/components/schemas/AuthenticationMessageError"
}
]
},
"examples": {
"missingAuthentication": {
"value": {
"status": "error",
"error": "Exactly one of x-api-key or Authorization must be provided"
}
},
"invalidCredential": {
"value": {
"status": "error",
"message": "Unauthorized"
}
}
}
}
}
},
"403": {
"description": "The authenticated account cannot select the requested workspace.",
"headers": {
"Cache-Control": {
"description": "Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.",
"schema": {
"type": "string",
"const": "private, no-store"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationRegistrationError"
},
"example": {
"status": "error",
"error": "Workspace not available"
}
}
}
},
"503": {
"description": "The preflight could not complete safely. Infrastructure details are not returned.",
"headers": {
"Cache-Control": {
"description": "Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.",
"schema": {
"type": "string",
"const": "private, no-store"
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ApplicationRegistrationError"
},
"example": {
"status": "error",
"error": "Could not validate application registration"
}
}
}
}
}
}Before connecting an external app, check its proposed name, environment, origins and return URLs. A successful result means those values passed validation for the selected workspace. It does not prove domain ownership.
What happens
The preflight runs after normal Recoup authentication. First-time sign-in can perform normal account provisioning and send its welcome email. After that, this validator does not persist an application or issue application credentials. It does not edit provider callbacks, create fan identities or sessions, allocate capacity, or authorize purchases and spending.
workspace_id and billing_owner_id come from the authenticated account or an
organization it can access. They describe the proposed owner only. Supplying
organization_id does not grant workspace access. Do not submit account or
billing ownership overrides, secrets or tokens in the proposal.
The result is flat and includes status: "validated", persisted: false and
origins_verified: false. It contains no application ID or token to install.
Addresses and environments
- Choose
developmentorproductionexplicitly for each proposal. - Use exact canonical origins such as
https://music.example, without a trailing slash, wildcard, path, credentials, query or fragment. Different hosts and ports are different origins. - HTTPS is required. Development also accepts HTTP on
localhost,127.0.0.1and[::1]; these loopback hosts are rejected in production. - A return URL must be an exact canonical URL on one of the proposed origins,
without credentials or fragments. For a bare host use its canonical trailing
slash, such as
https://music.example/. Query strings are retained literally. - Each list takes 1–32 distinct addresses, each at most 2048 characters. The name is trimmed and must then contain 1–120 characters. These are input limits, not subscription or usage allowances.
Matching a return URL to a caller-proposed origin does not establish that the caller owns either address. No DNS check, URL fetch or domain proof is performed.
Standard MCP
On a standard API-key MCP connection that exposes validate_application_registration,
use the same proposal fields as HTTP. Account identity comes from the connection;
do not add account_id or extract a host-managed OAuth token.
{
"name": "Release companion",
"environment": "production",
"allowed_origins": ["https://music.example"],
"return_urls": ["https://music.example/listen?connected=spotify"]
}Delegated OAuth excludes this tool, including connections with mcp:tools.
HTTP and standard MCP share proposal validation; their transport-specific error
envelopes differ. HTTP authentication errors can use error or message, while
handled preflight errors use status: "error" and error. MCP failures are tool
errors or SDK input-validation errors. None confirms registration or activation.
See authentication and MCP connection guidance. Application persistence, origin proof/reverification, provider configuration, fan bootstrap, suspension and quota policy require their own completed contracts.