API REFERENCE

Check an application proposal

On this page
POST/api/applications/registration/validate

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.

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
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 for this request
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

namestringrequired

Whitespace is trimmed before requiring 1–120 characters. The response returns the trimmed name.

minLength: 1

organization_idstring

Optional 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 · enumrequired

Required; this proposal checks one environment. This does not create environment resources or allowances.

Values: "development", "production"

allowed_originsarray<string>required

Distinct 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>required

Distinct 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

Request example
{
  "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 header

Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.

application/json

statusstringrequired
persistedbooleanrequired

The preflight did not persist an application or registration.

origins_verifiedbooleanrequired

No domain-ownership proof was checked.

workspace_idstringrequired

Workspace derived from authentication and the authorized optional organization selection.

format: uuid

billing_owner_idstringrequired

Same proposed owner as workspace_id. Attribution only: no subscription, quota, top-up or spending authority is granted.

format: uuid

namestringrequired

minLength: 1 · maxLength: 120

environmentstring · enumrequired

Required; this proposal checks one environment. This does not create environment resources or allowances.

Values: "development", "production"

allowed_originsarray<string>required

Distinct 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>required

Distinct 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

200 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"
  ]
}

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 header

Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.

application/json

statusstringrequired
errorstringrequired
400 example
{
  "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
statusstringrequired
errorstringrequired
anyOf · AuthenticationMessageError 2
statusstringrequired
messagestringrequired
missingAuthentication
{
  "status": "error",
  "error": "Exactly one of x-api-key or Authorization must be provided"
}

invalidCredential
{
  "status": "error",
  "message": "Unauthorized"
}

403The authenticated account cannot select the requested workspace.
Cache-Controlresponse header

Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.

application/json

statusstringrequired
errorstringrequired
403 example
{
  "status": "error",
  "error": "Workspace not available"
}

503The preflight could not complete safely. Infrastructure details are not returned.
Cache-Controlresponse header

Preflight success and handled validation/workspace/infrastructure failures are private, no-store. Authentication failures return before these headers are added.

application/json

statusstringrequired
errorstringrequired
503 example
{
  "status": "error",
  "error": "Could not validate application registration"
}

Full specification

Download the OpenAPI file for complete schemas, constraints, and examples.

Download applications.json
View operation source
json
{
  "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 development or production explicitly 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.1 and [::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.

json
{
  "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.

Get started with Recoup.