API para agentes de GetFacade

Diseño de fachada sobre MCP y HTTP. Cada diseño se elabora para el país donde está el edificio: materiales aplicables allí, productos que los fabricantes venden realmente allí y la composición técnica detrás de la superficie. Un render lo muestra sobre la foto de la casa, el presupuesto lo valora línea a línea y el álbum PDF lo documenta para la empresa que lo ejecuta. Cada ruta de abajo es un endpoint existente de GetFacade, el mismo que llaman las apps de iOS, Android y web. Una clave de agente solo acota quién puede llamarlo, mide lo que gasta y se detiene en su tope.

URL base
https://api.getfacade.ai/api/v1
Autenticación
Bearer <agent key>
Paquete
@getfacade/mcp
Entorno de ejecución
Node.js 20+
Transporte
stdio (MCP), HTTPS (REST)
Especificación
OpenAPI 3.1, v1.0.0

Inicio rápido

  1. Emitir una clave

    app.getfacade.aiCuentaConfiguraciónAPICrear clave

    El valor se muestra una sola vez y no se puede recuperar, solo reemplazar. El tope de gasto se fija al emitirla y se aplica en cada llamada de pago.

    Emitir una clave de agente
  2. Registrar el servidor MCP

    Una entrada en la configuración del cliente y, después, reiniciar el cliente. Claude Desktop la guarda en claude_desktop_config.json; cualquier otro cliente MCP admite los mismos tres campos.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Variables de entorno
    VariableObligatoriaValor por defecto
    GETFACADE_API_KEY
    GETFACADE_API_BASE_URLNohttps://api.getfacade.ai/api/v1
  3. O llamar directamente a la API HTTP

    La misma clave sirve como token Bearer. Peticiones y respuestas son documentos JSON:API, donde id es un campo de primer nivel y nunca está dentro de attributes.

    shell
    curl -X POST https://api.getfacade.ai/api/v1/projects \
      -H "Authorization: Bearer $GETFACADE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"data":{"type":"project","attributes":{"name":"Maple Street 14"}}}'

Herramientas

Veintiuna herramientas. El servidor MCP no guarda estado ni reglas propias: cada herramienta es una o varias llamadas a los endpoints indicados al lado, y cada mensaje que el agente repite lo escribe la API.

  • create_building
    create_building(name, goals?, construction_region?)
      -> { building_id, name }

    Crea un edificio. El nombre es único dentro de la cuenta y tiene 50 caracteres como máximo; un duplicado se rechaza con 422.

    Llama aPOST /projects

  • upload_photo
    upload_photo(building_id, file_path, wait_for_validation? = true)
      -> { view_id, validation: { status, reason? } }

    Registra una vista, sube los bytes a una URL prefirmada, los confirma y consulta hasta que la foto se acepta o se rechaza. Ancho, alto y md5 se calculan localmente; la relación de aspecto la deduce el servidor.

    Llama aPOST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validation

  • start_designasíncrona
    start_design(building_id, view_id, prompt?, style_ids?, colors?,
                 brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, seed }

    Diseña la fachada sobre una vista elegida y la muestra en la foto: materiales aplicables en el país del edificio, productos que allí se venden de verdad y la composición que hay detrás de la superficie. Crea un diseño, encola el trabajo y devuelve el id del trabajo. La semilla es opcional: si se omite, el servidor la genera y la devuelve.

    Llama aPOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

  • refine_designasíncrona
    refine_design(render_id | design_id + building_id, instruction,
                  style_ids?, colors?, brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, parent_render_id, seed }

    Revisa con palabras un diseño terminado. La instrucción se aplica al diseño terminado, así que se conserva todo lo que no menciona. Revisar una vista principal crea un diseño nuevo, de modo que el anterior nunca se sobrescribe.

    Llama aGET /renders/{render} → POST /concepts/{concept}/angles/{conceptAngle}/renders (mode: refine)

  • get_job
    get_job(job_id, kind: "render" | "album" | "estimate" = "render")
      -> { status, expected_seconds?, result_url?, error?, error_code? }

    Lee el estado de un render, un presupuesto o un álbum.

    Llama aGET /renders/{render} · GET /estimates/{estimate}

  • list_jobs
    list_jobs(kind?, limit? = 20)
      -> [{ job_id, kind, status, building_id, created_at }]

    Trabajos recientes de la cuenta, los no terminados primero.

    Llama aGET /history

  • list_designs
    list_designs(building_id)
      -> [{ design_id, note, has_main_render, main_render_id,
           main_render_url, renders }]

    Diseños de un edificio con sus renders. De aquí salen los identificadores de render para un presupuesto o un álbum.

    Llama aGET /projects/{project}/concepts

  • order_estimateasíncrona
    order_estimate(design_id, render_ids, currency?,
                   measurement_system?, special_requirements?)
      -> { job_id, status }

    Valora el diseño línea a línea, en materiales y mano de obra, al precio que tienen esos materiales en el país del edificio. La moneda y el sistema de medida se toman por defecto de ese país.

    Llama aPOST /projects/{project}/concepts/{concept}/estimates

  • order_albumasíncrona
    order_album(design_id, render_ids, language?, include_blueprints?,
                include_estimate?, requirements?)
      -> { job_id, status }

    Documenta el diseño para la empresa que lo ejecuta: los materiales, la composición de la fachada, las notas de seguridad y las normas que las respaldan. Requiere un render principal terminado.

    Llama aPOST /concepts/{concept}/album/generate

  • upscale_renderasíncrona
    upscale_render(render_id)
      -> { job_id, status }

    Amplía un render terminado. Cuesta tokens y se ejecuta de forma asíncrona.

    Llama aPOST /renders/{render}/upscale

  • get_estimate
    get_estimate(estimate_id)
      -> { status, currency, facade_area, materials_total, labor_total,
           grand_total, notes, lines: [{ line_id, section, name, quantity,
           unit, unit_price, line_total }] }

    El presupuesto en sí: totales, los supuestos que los sustentan y cada línea con cantidad, unidad y precio. get_job informa del estado de un presupuesto, nunca de su contenido.

    Llama aGET /estimates/{estimate}

  • add_estimate_line
    add_estimate_line(estimate_id, section, name, quantity,
                      unit_price, unit?, category?)
      -> { line_id }

    Añade una línea al presupuesto. Las unidades salen de su propio sistema de medida.

    Llama aPOST /estimates/{estimate}/items

  • update_estimate_line
    update_estimate_line(estimate_id, line_id, name?, quantity?,
                         unit_price?, unit?, category?, section?)
      -> { line_id }

    Cambia una línea del presupuesto. Solo se tocan los campos enviados; el servidor recalcula los totales.

    Llama aPATCH /estimates/{estimate}/items/{item}

  • delete_estimate_line
    delete_estimate_line(estimate_id, line_id)
      -> { deleted }

    Elimina una línea del presupuesto.

    Llama aDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Elimina un render. Al borrar el render principal, su diseño vuelve a borrador.

    Llama aDELETE /renders/{render}

  • delete_design
    delete_design(building_id, design_id)
      -> { deleted }

    Elimina un diseño con los renders que contiene.

    Llama aDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Elimina un edificio con todo lo que contiene. Los tokens ya gastados no se devuelven.

    Llama aDELETE /projects/{project}

  • list_token_packages
    list_token_packages()
      -> [{ package, tokens, price, currency }]

    Los paquetes que esta cuenta puede comprar, con su precio y su número de tokens.

    Llama aGET /tokens/packages

  • buy_tokensasíncrona
    buy_tokens(package)
      -> { status, transaction_id, tokens, checkout_url?, detail }

    Compra un paquete para la cartera de esta clave. Requiere una clave emitida con la compra habilitada y nunca supera lo que la clave aún puede gastar.

    Llama aPOST /tokens/purchase

  • get_balance
    get_balance()
      -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }

    Monedero del agente, tope de esta clave y si se admitirá la próxima llamada de pago.

    Llama aGET /tokens/balance

  • report_problem
    report_problem(message, category?,
                   context?: { tool, endpoint, status_code, job_id,
                               expected, actual })
      -> { reference, message }

    Informa de un defecto de esta API: un campo descrito aquí que nunca llega, un rechazo cuya redacción no deja salida, un resultado que no corresponde a lo pedido. Gratuito y aceptado con el saldo a cero; devuelve una referencia, no una respuesta.

    Llama aPOST /feedback

Autenticación y claves

  • La clave viaja como token Bearer en la cabecera Authorization. El servidor MCP la lee de GETFACADE_API_KEY y no envía nada más.
  • El valor se muestra una vez, al emitirlo, y solo se guarda su hash. Rotar significa emitir una clave nueva y revocar la anterior.
  • Cada clave lleva un tope de gasto que se aplica en el servidor antes de que la llamada llegue a un controlador. Alcanzar el tope detiene esa clave, no la cuenta.
  • Las claves no gestionan claves: eso es una acción humana, y esos endpoints responden 403 a una clave de agente.
  • La revocación surte efecto de inmediato. Las llamadas con una clave revocada responden 401.

Trabajo asíncrono y consulta de estado

  • start_design, order_estimate y order_album devuelven un identificador de trabajo y terminan. Un render tarda minutos: consulte GET /renders/{render} o GET /estimates/{estimate} hasta que el estado sea terminal.
  • El fin de la validación de la foto lo anuncia un websocket del que el agente no dispone. Consulte GET /angles/{angle}/validation y lea validation.is_in_progress; no deduzca usted mismo la terminalidad de la cadena de estado.
  • Un render terminado y un álbum terminado viven en URL públicas permanentes: sin firma y sin caducidad. El enlace se le puede dar directamente a una persona, como respuesta a «enséñame el resultado». Al no estar firmado no pide permiso a nadie: sigue funcionando para cualquiera que lo reciba y no se puede revocar.
  • GET /renders/{render}/download es otra cosa: una URL firmada que caduca en minutos y lleva un nombre de archivo. Sirve para guardar el archivo, no para compartirlo.

Límites de frecuencia por clave

Una clave de agente tiene sus propios cupos, separados de las sesiones humanas de la misma cuenta, para que un agente en bucle no consuma el cupo de quien está frente a la pantalla. El rechazo es barato: se decide en el middleware, antes de cualquier trabajo en la base de datos.

ÁmbitoPor minutoPor hora
Lecturas y escrituras ordinarias1202000
Consulta de estados y de validación1202000
Encargos de render, presupuesto y álbum10200

Idempotencia

Una llamada de pago crea un trabajo, y el cargo sigue al trabajo. Poner nombre a la llamada es lo que permite que un reenvío devuelva el mismo trabajo en vez de crear un segundo.

  • Idempotency-Key es obligatoria en toda llamada de pago hecha con una clave API: iniciar o retocar un diseño, ampliar un render, pedir un presupuesto o un álbum, regenerar un presupuesto. Sin ella la llamada responde 422 IDEMPOTENCY_KEY_REQUIRED y no se encola nada.
  • Cualquier valor de 8 a 191 caracteres, uno por pedido; lo habitual es un UUID. Un pedido nuevo lleva un valor nuevo: dos llamadas idénticas bajo dos valores son dos diseños.
  • Repetir una llamada con el mismo valor y el mismo cuerpo devuelve el estado y el cuerpo originales, con Idempotent-Replay: true en la respuesta. No se encola nada ni se cobra dos veces.
  • El mismo valor con un cuerpo distinto responde 422 IDEMPOTENCY_KEY_REUSED. Un reenvío que llega mientras la primera llamada sigue en curso responde 409 IDEMPOTENCY_IN_PROGRESS: espera y envía la misma llamada otra vez.
  • Cualquier 4xx libera el valor, así que se puede volver a enviar una vez corregida la causa. Los valores se recuerdan 24 horas, por cuenta.
  • @getfacade/mcp genera el valor y reintenta con él por su cuenta, así que en la llamada a la herramienta no hay que pasar nada.

Errores

Los fallos llegan como documentos de error JSON:API. Las respuestas de validación de Laravel no tienen forma JSON:API y llevan su texto en message.

EstadoCódigoSignificadoReintentable
401La clave falta, está revocada o ha caducado.No
402AGENT_CREDITS_EXHAUSTEDLa cuenta no tiene créditos de ámbito api.No
402AGENT_KEY_CAP_REACHEDEsta clave ha agotado su tope. Emita otra clave o suba el tope.No
403Este endpoint no está disponible para claves de API. La API para agentes abarca edificios, fotos, diseños, renders, presupuestos, álbumes y el monedero de API. Los ajustes de cuenta, inicio de sesión y pago los cambia una persona que ha iniciado sesión en la aplicación.No
403AGENT_PURCHASE_NOT_ALLOWEDEsta clave se emitió sin permiso para comprar tokens.No
403AGENT_PURCHASE_EXCEEDS_CAPLa compra dejaría la clave por encima de su límite de gasto.No
409IDEMPOTENCY_IN_PROGRESSLa primera llamada con este Idempotency-Key aún no ha respondido. Espera y envía la misma llamada de nuevo.
422La petición se entendió y se rechazó: nombre de edificio duplicado, foto rechazada, álbum encargado antes de terminar el render principal.No
422IDEMPOTENCY_KEY_REQUIREDUna llamada de pago con clave API y sin cabecera Idempotency-Key. No se encoló nada; vuelve a enviarla con la cabecera.No
422IDEMPOTENCY_KEY_REUSEDEste Idempotency-Key se usó para otra solicitud. Usa un valor nuevo para un pedido nuevo.No
429El cupo propio de esta clave está agotado. Espere, no reintente en bucle cerrado.

El texto legible lo escribe la API, en el idioma de quien llama. Muestre errors[].detail tal cual en lugar de componer su propio mensaje.

Facturación y admisión

  • Las llamadas de pago consumen créditos del ámbito api, y la admisión solo mira ese saldo: cada clave paga en créditos.
  • Un Pro Plan activo repone la cartera api hasta 1000 créditos una vez por periodo de facturación. Más allá, los créditos se compran.
  • Una clave recarga su cartera solo si se emitió con la compra habilitada, y solo hasta lo que aún puede gastar, así que una compra nunca sube el límite de gasto.
  • El ámbito api es un monedero aparte. Los créditos de la aplicación, incluida la capa gratuita, nunca los gasta una clave.
  • El gasto se mide por clave, así que el consumo de cada asistente se ve por separado.
  • La comprobación previa es GET /tokens/balance, campo data.attributes.agent.is_admissible. El bloque solo aparece en claves de agente y el indicador refleja exactamente el middleware de admisión. Léalo en lugar de comparar el saldo con el tope.
  • La admisión se decide antes de encolar trabajo, así que una llamada rechazada no gasta nada.

Tokens de color y de marca

start_design admite dos listas independientes de diez entradas como máximo. El orden lleva el papel 60/30/10: la primera entrada es el color dominante de los muros.

colors

TokenSignificado
palette:1Una combinación de GetFacade, por identificador.
#8A8F7DUn color libre, seis dígitos hexadecimales.
paint:412Una muestra de fabricante, en la forma de dos segmentos que se mantiene por compatibilidad.

brand_selections

TokenSignificado
siding:brand:12Cualquier producto de ese fabricante en esa categoría.
siding:line:40@double-4-dutchlapUna línea, sobre una geometría.
siding:product:88@double-4-dutchlapUn producto, totalmente especificado.
paint:brand:3Cualquier color de esa marca de pintura.
paint:product:412Una muestra de pintura.

La gramática es category:level:id[@value][.value]. La parte tras @ lleva slugs de valores de geometría, únicos dentro de su categoría, de modo que el eje al que pertenecen se busca en lugar de escribirse en el token. Un token desconocido se rechaza con 422 y nunca se ignora en silencio.

Sesión de principio a fin

Un edificio, una foto, un diseño y luego los dos documentos. La instrucción que lo produce:

Crea un edificio llamado Maple Street 14, sube ./front.jpg como su vista e inicia un diseño con muros gris cálido y molduras blancas. Encarga el presupuesto y el álbum del resultado.
Sesión MCP
create_building(name: "Maple Street 14")
  -> { building_id: "0f8c…" }

upload_photo(building_id: "0f8c…", file_path: "./front.jpg")
  -> { view_id: "41ab…", validation: { status: "approved" } }

start_design(building_id: "0f8c…", view_id: "41ab…",
             colors: ["#8A8F7D", "#F2F0EB"],
             brand_selections: ["siding:line:40@double-4-dutchlap"])
  -> { design_id: "7d21…", job_id: "b933…", status: "queued" }

get_job(job_id: "b933…")
  -> { status: "completed", result_url: "https://…" }

refine_design(render_id: "b933…",
              instruction: "put a canopy over the front door")
  -> { design_id: "9e44…", job_id: "c07f…", status: "queued" }

order_estimate(design_id: "9e44…", render_ids: ["c07f…"])
order_album(design_id: "9e44…", render_ids: ["c07f…"], include_estimate: true)

Recursos