# Check a spec without submitting it {#top}

**Read** · `POST /v1/tenants/{tenant}/specs/validate` · MCP tool `validate`

Runs the same checks as `submit` and tells you what `submit` would answer. Nothing is stored and no build starts, so you can run it as often as you like.

Roles that can call it: `builder`, `deployer`.

## Parameters

| Name | In | Required | Description |
|---|---|---|---|
| `tenant` | path | yes | Your tenant ID |
| request body | body | yes | The image spec to check |

## Returns

A JSON object with these keys: `tenant`, `valid`, `spec_hash`, `problems`, `gates`, `guarantee`, `caller_authenticated`.

## Example request

```sh
curl -X POST https://api.tarsana.io/v1/tenants/acme/specs/validate \
  -H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
  -H 'X-Tarsana-Tenant: acme' \
  -H "Content-Type: application/json" \
  --data @spec.json
```

## Example response

```json
{
  "tenant": "acme",
  "valid": true,
  "spec_hash": "sha256:cdff062988d4722b2ff052c97ebefb8b571858c493ce47b159df73b1c88809b1",
  "problems": [],
  "gates": [
    {
      "gate": "tenant_name",
      "verdict": "pass",
      "status": "wired",
      "detail": "A sentence about this check.",
      "report": null
    },
    {
      "gate": "spec_schema",
      "verdict": "pass",
      "status": "wired",
      "detail": "A sentence about this check.",
      "report": null
    },
    {
      "gate": "policy_precheck",
      "verdict": "pass",
      "status": "wired",
      "detail": "A sentence about this check.",
      "report": {
        "violations": [],
        "warnings": []
      }
    }
  ],
  "guarantee": "namespaces are separated, callers are not authenticated",
  "caller_authenticated": false
}
```

## Errors

| Code | HTTP | What it means |
|---|---|---|
| [`invalid_parameter`](/api/errors#invalid_parameter) | 400 | A value in your request does not have the expected format, for example a submission ID that is not a spec hash. Check the value against the field's description and try again. |
| [`tenant_refused`](/api/errors#tenant_refused) | 400 | This tenant ID is not allowed, or is not in the expected format. Use a different ID made of lower-case letters, digits, dots, dashes and underscores. |
| [`spec_invalid`](/api/errors#spec_invalid) | 400 | Your spec does not match the spec format. Fix each problem listed in the response, at the path it gives, and send the spec again. |
| [`spec_unreadable`](/api/errors#spec_unreadable) | 400 | The request has no spec, or the spec could not be parsed. Send the spec as valid JSON, or as a YAML or JSON file on the command line. |
| [`policy_denied`](/api/errors#policy_denied) | 400 | Your spec breaks one or more rules of the security policy. Change your spec to meet each rule listed in the response, then submit it again. |
| [`no_acting_tenant`](/api/errors#no_acting_tenant) | 400 | Your request does not say which tenant you are acting for. Send your tenant ID in the `X-Tarsana-Tenant` header, or with `--as` on the command line. |
| [`isolation_refused`](/api/errors#isolation_refused) | 403 | This address belongs to a tenant ID you do not have access to. Check the tenant ID in the address and in your request header. |
| [`policy_unavailable`](/api/errors#policy_unavailable) | 503 | Your spec could not be checked against the security policy, so it was not accepted. This is a problem on our side: try again later, or contact Tarsana support. |
| [`unauthenticated`](/api/errors#unauthenticated) | 401 | Your request has no credential, or one that Tarsana does not recognise. Sign in with `login`, or send a valid access token. |
| [`forbidden`](/api/errors#forbidden) | 403 | Your role does not allow this operation. The response names the roles that do; ask for a credential with one of them. |
| [`rate_limited`](/api/errors#rate_limited) | 429 | You sent too many requests in a short time. Wait for the number of seconds in `retry_after_seconds`, then try again. |
| [`surface_fault`](/api/errors#surface_fault) | 500 | Something went wrong on our side. Try again later, and contact Tarsana support if it keeps happening. |
