# Envía una solicitud con la API REST

Crea un token de API, lee las claves de campo de un formulario, y crea una solicitud precompletada con curl, desde cualquier herramienta que pueda hacer una llamada HTTP.

## Envía una solicitud con la API REST

Cualquier herramienta con un paso HTTP puede enviar una solicitud: Pipedream, una función serverless, un script. Esta guía lo hace con curl, para que veas cada llamada antes de moverla a tu propio código.

<p>
  Necesitas un formulario publicado. Esta guía usa el que se construyó en{' '}
  <a href="/es/guides/ai-agents/build-a-form">Construye un formulario con un agente de IA</a>: nombre de la empresa, correo de contacto,
  número de IVA, una pregunta de sí o no sobre las condiciones de pago, y una subida de archivo. Cada método y opción usados aquí se
  describen en <a href="/es/developers/rest-api">Métodos de la API</a>.
</p>

<h2 id="token">1. Crea un token de API</h2>

<p>
  En formbase, abre <strong>OAuth y claves de API</strong> en la barra lateral del espacio de trabajo y{' '}
  <a href="/es/developers/api-tokens#create">crea un token</a>. El valor se muestra una sola vez. Guárdalo en una variable de entorno, nunca
  en tu código:
</p>

```
export FORMBASE_TOKEN='fb_...'
```

<p>
  Un token llega solo al espacio de trabajo en el que se creó. Cada llamada de abajo es un <code>POST</code> a la misma URL con el token en
  la cabecera <code>Authorization</code>; el cuerpo nombra el método y sus parámetros.
</p>

<h2 id="form-id">2. Encuentra el ID del formulario</h2>

<p>
  Abre el formulario en el editor. El ID del formulario es la parte de la dirección después de <code>/forms/</code>:
</p>

```
https://app.formbase.so/<workspace ID>/forms/jx75hdx8vb5hy1x85gm17nqgkn8f674g/edit
```

<p>Los comandos de abajo usan el ID de formulario de esta guía. Pon el tuyo en su lugar.</p>

<h2 id="fields">3. Enumera las claves de campo</h2>

<p>
  Una solicitud rellena preguntas, y las respuestas vuelven, por <a href="/es/requests/field-keys">clave de campo</a>. Pídele al formulario
  sus claves en lugar de adivinarlas a partir de los títulos:
</p>

```
curl -X POST https://api.formbase.so/api/v1 \
  -H "Authorization: Bearer $FORMBASE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"method": "fields.list", "params": {"formId": "jx75hdx8vb5hy1x85gm17nqgkn8f674g"}}'
```

<p>La respuesta enumera cada pregunta del formulario publicado. Resumida:</p>

```
{
  "ok": true,
  "data": {
    "published": true,
    "items": [
      { "key": "company_name", "type": "text", "title": "Company name", "required": true, "prefillable": true },
      { "key": "contact_email", "type": "email", "title": "Contact email", "required": true, "prefillable": true },
      { "key": "vat_number", "type": "text", "title": "VAT number", "required": false, "prefillable": true },
      {
        "key": "do_you_accept_our_30_day_payment_terms", "type": "radio", "title": "Do you accept our 30-day payment terms?", "required": true, "prefillable": true,
        "options": [{ "key": "yes", "label": "Yes" }, { "key": "no", "label": "No" }]
      },
      { "key": "certificate_of_incorporation", "type": "file", "title": "Certificate of incorporation", "required": true, "prefillable": false }
    ],
    "hasMore": false
  }
}
```

<p>
  Para precompletar una pregunta de elección, envía la <code>key</code> de la opción, aquí <code>"yes"</code>, no su etiqueta. Una pregunta
  con <code>prefillable: false</code>, como la subida de archivo, solo la puede responder el destinatario. El resto de las marcas se
  explican en <a href="/es/developers/rest-api#fields-list">fields.list</a>.
</p>

<h2 id="create">4. Crea una solicitud de prueba</h2>

<p>
  Envía la solicitud a Ada Lovelace, con el nombre de la empresa rellenado y bloqueado. <code>test: true</code> la convierte en una{' '}
  <a href="/es/requests/creating-requests#test-mode">solicitud de prueba</a>: nunca envía correo a nadie y no cuenta en ningún sitio, así
  que puedes repetir este paso tantas veces como quieras, con una nueva <code>idempotencyKey</code> cada vez.
</p>

```
curl -X POST https://api.formbase.so/api/v1 \
  -H "Authorization: Bearer $FORMBASE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "requests.create",
    "params": {
      "formId": "jx75hdx8vb5hy1x85gm17nqgkn8f674g",
      "recipient": { "email": "ada@acme.example", "name": "Ada Lovelace" },
      "prefill": { "company_name": "Analytical Engines Ltd" },
      "readonly": ["company_name"],
      "externalId": "supplier-2043",
      "idempotencyKey": "supplier-2043",
      "test": true
    }
  }'
```

<ul>
  <li>
    <strong>prefill</strong> rellena respuestas que el destinatario todavía puede cambiar. Una clave en <strong>readonly</strong> queda{' '}
    <a href="/es/requests/creating-requests#locked-fields">bloqueada</a> además.
  </li>
  <li>
    <strong>externalId</strong> es tu propio id para este trabajo, como un número de proveedor. Vuelve en cada lectura y cada callback.
  </li>
  <li>
    <strong>idempotencyKey</strong> hace que un reintento sea seguro. Si tu código envía la misma llamada dos veces, formbase devuelve la
    primera solicitud con <code>deduplicated: true</code> en lugar de crear una segunda.
  </li>
</ul>

<p>La respuesta lleva el ID de la solicitud y el enlace para el destinatario:</p>

```
{
  "ok": true,
  "data": {
    "id": "m17ayhcnj9xvzkff3atek49bdd8f6872",
    "status": "pending",
    "url": "https://form.formbase.so/r/rq_...",
    "deliveryStatus": "not_requested",
    "externalId": "supplier-2043",
    "deduplicated": false,
    "createdAt": 1790539225370,
    "expiresAt": 1793131225370
  }
}
```

<p>
  <code>deliveryStatus: "not_requested"</code> significa que formbase no envió ningún correo; tú entregas el enlace. Para que formbase envíe
  la invitación y los recordatorios, añade <code>"delivery": "email"</code>, que necesita un plan Pro o Business. Consulta{' '}
  <a href="/es/requests/invitations-and-reminders">Invitaciones, recordatorios y expiración</a>. Si el formulario tiene{' '}
  <strong>Enviar recordatorios</strong> activado, una solicitud real con un correo de destinatario igualmente recibe los recordatorios
  programados; añade <code>"reminders": []</code> para no enviar ninguno.
</p>

> ℹ️ **Las solicitudes de prueba quedan fuera de la vista**
> <p>
>     La página <strong>Solicitudes</strong> lista las solicitudes de prueba solo cuando activas el filtro{' '}
>     <strong>Mostrar solicitudes de prueba</strong>. Abre el <code>url</code> tú mismo para completarla. Quita <code>test</code> cuando
>     envíes la solicitud real.
>   </p>

<h2 id="read">5. Complétala y lee las respuestas</h2>

<p>
  Abre el <code>url</code> en un navegador. El nombre de la empresa está rellenado y bloqueado; responde el resto y envíalo. Luego lee la
  solicitud de vuelta con su ID:
</p>

```
curl -X POST https://api.formbase.so/api/v1 \
  -H "Authorization: Bearer $FORMBASE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"method": "requests.get", "params": {"requestId": "m17ayhcnj9xvzkff3atek49bdd8f6872"}}'
```

<p>
  Una vez que <code>status</code> es <code>completed</code>, la respuesta lleva dos mapas indexados por clave de campo. <code>answers</code>{' '}
  es para código: una respuesta de elección es la clave de la opción, una respuesta de archivo es una lista de archivos con URLs de
  descarga. <code>display</code> es para personas: etiquetas y nombres de archivo.
</p>

```
"answers": {
  "company_name": "Analytical Engines Ltd",
  "do_you_accept_our_30_day_payment_terms": "yes",
  "certificate_of_incorporation": [{ "name": "certificate-of-incorporation.pdf", "type": "application/pdf", "size": 635, "url": "https://api.formbase.so/api/storage/..." }]
},
"display": {
  "company_name": "Analytical Engines Ltd",
  "do_you_accept_our_30_day_payment_terms": "Yes",
  "certificate_of_incorporation": "certificate-of-incorporation.pdf"
}
```

<p>
  Preguntar una y otra vez hasta que cambie el estado funciona para una prueba, pero no en producción. Dale a la solicitud una{' '}
  <code>callbackUrl</code> y formbase te llama cuando termina; la siguiente guía lo configura.
</p>

<h2 id="next">Siguiente</h2>

<div class="not-prose grid gap-3 sm:grid-cols-2 mb-8">
  - [Recibe y verifica el callback](/es/guides/rest-api/verify-the-callback) — Recibe las respuestas en tu endpoint, y comprueba que las envió formbase.
  - [Crear una solicitud](/es/requests/creating-requests) — Cada opción que admite una solicitud: contexto, metadatos, documentos, expiración.
</div>
