15Referencia de las operaciones

Sección 15

Referencia de las operaciones

.md

Las ocho operaciones de /v1, con su permiso, su unidad de cobro y su contrato de entrada. La forma del sobre y de los errores está en las páginas 14 y 16.

Todos los nombres de campo van en snake_case, igual que el sobre de uso y el cuerpo de error.

Resumen

OperaciónPermisoSe factura comoUnidadRespuesta
POST /v1/vision/analysisvision:analyzeimage_analysisimagen200 con sobre
POST /v1/documents/analysisdocuments:analyzedocument_analysisdocumento200 con sobre
POST /v1/video/analysisvideo:analyzevideo_analysisvideo200 con sobre
POST /v1/audio/transcriptionsaudio:transcribeaudio_transcriptionsegundo200 con sobre
POST /v1/audio/speechspeech:synthesizetts_synthesiscarácter200 binario
POST /v1/text/sentimentsentiment:analyzesentiment_analysispetición200 con sobre
POST /v1/callscalls:initiatevoice_call_minuteminuto202 con acuse
POST /v1/agent/turnsagent:converseagent_turnpetición202 con acuse
GET /v1/jobs/{job_id}jobs:readno se cobra—200 (página 17)
GET /v1/agentsagents:readno se cobra—200 con la lista de sus agentes activos

Las seis primeras responden con el resultado en la misma llamada. Las dos asíncronas —la llamada y el turno— responden un acuse y el resultado llega después. Las dos últimas son LECTURAS y no cobran nada.

Hay una entrada más que no aparece arriba porque no es una operación que se pida, sino la lectura de una que ya pidió: el stream del turno, en GET /v1/agent/streams/{job_id}, cuya URL exacta le llega en el acuse. Lo autoriza jobs:read, y su contrato está en la página 19.

De dónde sale el agent_id

POST /v1/agent/turns y POST /v1/calls exigen un agent_id, y GET /v1/agents es el que se lo da: devuelve sus agentes activos con id, name y active. Nada más — la configuración del agente (capacidades, reglas, canales, voz) se gobierna en la consola y no viaja por esta API.

curl -sS -X GET "$ASIXTO_BASE_URL/v1/agents" \
  -H "Authorization: Bearer $ASIXTO_API_KEY"
JSON
{
  "data": [{ "id": "a4f1c2e0-6d3b-4e7a-9c21-8f0e5b7d4a13", "name": "Cobranza", "active": true }],
  "total": 1
}

Solo lista agentes que pueden atender un turno ahora mismo: uno desactivado no aparece, porque ofrecerle un agent_id que la operación siguiente rechaza con 400 sería peor que no ofrecerlo. Crear o editar agentes no está en /v1: eso vive en la consola, donde está su único escritor.

Devuelve hasta 100 agentes. total es el número real de activos, así que si su cuenta tuviera más de cien lo vería ahí, y la respuesta traería además omitted con cuántos no cupieron. No hay cursor ni páginas: los agentes se crean a mano en la consola y cien es holgado para cualquier cuenta. Si llega a ese punto, escríbanos (página 10) — preferimos hablarlo antes que publicar un formato de paginación que después no podríamos cambiar. El recorte conserva el orden, así que el agent_id que guarde no se le mueve.

Ojo con las claves que ya tenía emitidas: agents:read se concede al emitir, así que una clave anterior a este permiso responde 403 insufficient_scope aquí. Emita una nueva y rótela (página 9).

La lista se sirve con hasta 60 segundos de retraso: es la misma lectura que usa la consola y va cacheada por cuenta. Un agente que active ahora puede tardar ese minuto en aparecer aquí, así que no encadene «crear en la consola» con «listar por API» sin ese margen. Los agent_id no cambian, de modo que una vez obtenido puede guardarlo: esta ruta es para descubrirlo, no para consultarla en cada turno.

Los diez permisos de una clave

Una clave lleva los permisos que se le concedieron al emitirla, y son diez en total: uno por capacidad, más los dos de lectura. Una clave sin ninguno no autoriza nada y toda petición responde 403 insufficient_scope.

PermisoQué autorizaQué no autoriza
vision:analyzeAnalizar una imagenDocumentos, audio ni ninguna otra capacidad
documents:analyzeAnalizar un documento que usted aloja por URLSubir el archivo, ni analizar imágenes
video:analyzeAnalizar un video que usted aloja por URLDocumentos ni imágenes: cada capacidad lleva el suyo
audio:transcribeConvertir audio a textoGenerar audio: eso es speech:synthesize
speech:synthesizeGenerar audio a partir de textoLeer audio. Leer y generar son permisos distintos a propósito
sentiment:analyzeAnalizar el tono de un textoNada del turno del agente: el turno no lo hace por su cuenta
calls:initiateOriginar una llamada de voz con su agenteLeer la llamada: eso es jobs:read. Colgarla no existe en la API
jobs:readConsultar un trabajo y leer el stream de un turnoCrear nada. Es la única entrada que no gasta créditos ni cupo
agent:converseAbrir un turno de conversación con su agenteLeer la respuesta de ese turno: leerla la autoriza jobs:read
agents:readListar sus agentes activos para obtener el agent_idCrear, editar ni desactivar un agente: eso es de la consola

calls:initiate es «originar», no «llamadas». Un permiso de recurso genérico habría cubierto también leer o colgar, que son cosas que se pueden querer conceder sin conceder la de marcar: es la única operación de la superficie que gasta dinero por minuto en un tercero y expone su número al destinatario.

No hay verbo para colgar una llamada en curso, y no lo damos por supuesto. La API no publica ninguna ruta que corte una llamada ya originada: la llamada termina cuando la conversación termina, cuando se agota el plazo del trabajo o cuando un operador de su empresa pulsa el botón de parada desde la consola. Si necesita detener una llamada, ese es hoy el único camino. Tampoco hay estado canceled: los cinco valores de status son los de la página 17 y ninguno significa «cancelado».

jobs:read es el que le deja leer lo que pagó

Cubre dos entradas, y por eso es el que más falta se echa cuando no está: la consulta del trabajo (GET /v1/jobs/{job_id}, página 17) y la lectura del stream del turno, cuyo stream_url viene en el acuse de POST /v1/agent/turns.

Esa segunda ruta admite dos credenciales distintas para la misma autorización: su clave de API con jobs:read, y el token de sesión de nuestra consola con su propio permiso de lectura de conversación. El criterio es el mismo en los dos casos —quien paga el turno puede leer su respuesta— y un trabajo de otra cuenta responde igual que uno inexistente.

🔴 Sin jobs:read, un turno se paga y no se puede leer, y por eso toda clave nace con él. La emisión añade siempre jobs:read y agents:read a lo que usted marque: son las dos lecturas que no gastan créditos ni cupo, y sin ellas quien integra no puede leer lo que pagó ni descubrir el agent_id que las demás rutas le exigen (página 9). La otra cara —la que hay que tener presente al emitir— es que esas dos no se pueden dejar fuera: si su política es conceder el mínimo indispensable, cuente con ellas dentro y no espere una clave que las excluya. La expansión ocurre solo al emitir, así que una clave emitida antes de que uno de esos dos permisos existiera no lo gana por sí sola: hay que emitir otra y rotarla.

agent:converse no se concede «por si acaso»

Es la capacidad más cara de la superficie y la única que no se puede deshacer: abrir un turno gasta créditos, invoca las herramientas de su servidor —que pueden escribir en sus sistemas— y ya ocurrió. Concederlo a una clave emitida para transcribir audio es regalar eso. Es lo contrario de jobs:read: ahí lo que faltaba era una lectura inocua, aquí lo que sobra es una escritura irreversible.

Los permisos de una clave ya emitida no se editan desde la consola: si le falta uno, emita otra con lo que necesita, despliegue y revoque la anterior. Cada entorno admite dos claves activas justo para eso.

POST /v1/vision/analysis

Análisis de una imagen. multipart/form-data con un solo archivo.

CampoDóndeObligatorioLímite
fileparte del multipartsí10 MiB
curl -sS -X POST "$ASIXTO_BASE_URL/v1/vision/analysis" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Idempotency-Key: img-4471" \
  -F "file=@albaran.jpg"

result: analysis (la descripción), summary y degraded. Si el modelo no pudo leer la imagen, la operación no se cobra y responde el error de proveedor no disponible en vez de un análisis vacío.

POST /v1/documents/analysis

Análisis de un documento que usted aloja. Se envía la URL, no el archivo: su almacenamiento ya sabe servirlo con una URL firmada, y pedirle que nos lo suba sería mover megabytes dos veces.

CampoTipoObligatorioLímite
document_urltextosí1–2048 caracteres
mime_typetextosí1–255 caracteres
filenametextosí1–255 caracteres
curl -sS -X POST "$ASIXTO_BASE_URL/v1/documents/analysis" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: doc-4471" \
  -d '{"document_url":"https://archivos.suempresa.com/contrato.pdf","mime_type":"application/pdf","filename":"contrato.pdf"}'

result: extracted_text, summary y degraded.

Si no podemos descargar su documento —URL firmada caducada, su almacenamiento limitando la tasa, una cadena de redirecciones que no termina— recibe 422 document_unreachable, que existe para atribuirle el fallo a quien lo puede arreglar: la petición está bien escrita y el recurso al que apunta no se pudo procesar.

POST /v1/video/analysis

Análisis de un video que usted aloja, igual que el documento: se manda la URL en JSON, no el archivo.

CampoTipoObligatorioLímite
video_urltextosí1–2048 caracteres
mime_typetextosí1–255 caracteres, y ha de ser un tipo video/…
filenametextosí1–255 caracteres
duration_secondsenterono1 a 600 segundos
curl -sS -X POST "$ASIXTO_BASE_URL/v1/video/analysis" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: video-4471" \
  -d '{"video_url":"https://archivos.suempresa.com/entrega.mp4","mime_type":"video/mp4","filename":"entrega.mp4","duration_seconds":45}'

result: analysis (la descripción), summary y frames_analyzed. Un análisis que no se pudo hacer no se cobra: responde el error en vez de un informe vacío.

filename es solo para el informe y el registro: no se usa para resolver nada. mime_type que no sea de video se rechaza, porque esta operación analiza video y la imagen tiene la suya.

Los dos techos de la entrada

50 MiB y 600 segundos, y pasado cualquiera de los dos se rechaza nombrándolo, nunca recortando en silencio: un análisis de parte del video se cobraría igual que el completo.

TechoCómo se compruebaQué recibe si se pasa
50 MiBUn sondeo del enlace que usted declara413 payload_too_large, con los bytes que anuncia su origen
600 segundosLa duración que usted declara en duration_seconds400 validation_error, que nombra el campo

duration_seconds es opcional porque la declara usted: no sostenemos los bytes del video, así que no podemos medirla por nuestra cuenta. Cuando falta, el techo que acota lo que llega es el de tamaño. Y declararla de menos no abarata nada, porque el precio no depende de ella.

🔴 La tarifa es plana: 270 créditos por video (página 12). Un video de diez segundos y uno de cinco minutos cuestan lo mismo. Por eso la entrada tiene techos y por eso se rechaza en vez de recortar.

POST /v1/audio/transcriptions

Audio a texto. multipart/form-data, y el idioma va en la query.

CampoDóndeObligatorioLímite
fileparte del multipartsí25 MiB
languagequerynoISO 639-1, 2–5 caracteres

Formatos admitidos: FLAC, MP3, MP4, MPEG, MPGA, M4A, OGG, WAV y WEBM. Otro tipo recibe 415 unsupported_media_type con la lista, en vez de fallar más adelante.

curl -sS -X POST "$ASIXTO_BASE_URL/v1/audio/transcriptions?language=es" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Idempotency-Key: nota-4471" \
  -F "file=@nota.ogg"

Mande language solo con evidencia real del idioma. Forzar uno que no es el del audio no falla: el modelo traduce. Medido contra el proveedor — una nota en inglés con language=es vuelve en español. Sin el parámetro se autodetecta, que es el comportamiento correcto por omisión.

Se cobran 10 segundos como mínimo, porque es lo que factura el proveedor: una nota de tres segundos —el caso normal en un chat— cuesta diez. Va en usage.quantity, así que se puede conciliar.

result: text y filtered_hallucination. Un texto vacío con ese indicador puesto significa que descartamos lo único que devolvió el proveedor: eso no se cobra. Un texto vacío sin el indicador es un audio sin habla, y eso sí es un resultado.

POST /v1/audio/speech

Texto a voz. Devuelve el audio como cuerpo binario, siguiendo la convención de la industria, así que el sobre viaja en cabeceras.

CampoTipoObligatorioLímite
texttextosí1–5.000 caracteres
voice_idtextosí1–100 caracteres
model_idtextono1–100 caracteres
language_codetextono2–10 caracteres
voice_settingsobjetonose reenvía sin interpretarlo
speednúmerono0,25 a 4
curl -sS -X POST "$ASIXTO_BASE_URL/v1/audio/speech" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: voz-4471" \
  -d '{"text":"Su pedido llega el martes","voice_id":"es-CO-natural","speed":1}' \
  --output respuesta.mp3 -D cabeceras.txt
CabeceraQué trae
X-Asixto-Request-Idlo mismo que request_id
X-Asixto-Job-Idlo mismo que job_id
X-Asixto-Usage-Operationlo mismo que usage.operation
X-Asixto-Usage-Unitlo mismo que usage.unit
X-Asixto-Usage-Quantitylo mismo que usage.quantity
X-Asixto-Usage-Creditslo mismo que usage.credits
X-Asixto-Audio-Duration-Msduración del audio
X-Asixto-Chars-Inputcaracteres que usted envió
X-Asixto-Chars-Normalizeden qué se convirtió su texto
X-Asixto-Chars-Billedcaracteres cobrados

Las tres últimas están para que entienda por qué se le cobran más caracteres de los que escribió: el proveedor cobra el texto normalizado, y la normalización expande —«Dr.» se dice «Doctor», «999» se dice «novecientos noventa y nueve»—.

🔴 Es la única operación cuyo resultado no se puede reenviar. El resultado es el audio, y guardarlo significaría megabytes por petición y una copia durable de lo que usted dictó. Repetir su clave de idempotencia recibe 409 result_not_replayable y el cobro no se duplica: si necesita el audio otra vez, pida la síntesis con una clave nueva.

POST /v1/text/sentiment

CampoTipoObligatorioLímite
texttextosí1–10.000 caracteres
customer_idtextono1–128 caracteres
channeltextono1–64 caracteres
region_idtextono1–64 caracteres
curl -sS -X POST "$ASIXTO_BASE_URL/v1/text/sentiment" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: sent-4471" \
  -d '{"text":"Llevo tres días esperando y nadie me responde.","customer_id":"cliente-12345"}'

result: sentiment, score y source. customer_id es su identificador y es opaco para nosotros: se usa para la tendencia del sentimiento de ese cliente, nunca para resolver nada de nuestra base.

POST /v1/calls · asíncrona

Origina una llamada de voz con su agente. Responde 202 con un acuse: la conversación todavía no ha empezado.

CampoTipoObligatorioLímite
totextosíE.164 con + y país
agent_idtextosíidentificador de un agente de su cuenta
max_duration_secondsenterono1 a 900; sin él, 300
topictextonohasta 200 caracteres
variablesobjetonover contexto por petición
metadataobjetonoídem
curl -sS -X POST "$ASIXTO_BASE_URL/v1/calls" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: llamada-4471" \
  -d '{"to":"+573001112233","agent_id":"a4f1c2e0-6d3b-4e7a-9c21-8f0e5b7d4a13","max_duration_seconds":300,"topic":"cobro de la factura 4471"}'

Acuse: call_id, status (queued), max_duration_seconds, authorized_minutes y from.

max_duration_seconds del acuse puede ser MENOR que el que pidió: es la forma de saber, antes de que suene el teléfono, que su saldo solo paga parte de la conversación. La duración fuera de rango se rechaza, no se recorta en silencio, porque es lo que decide cuántos créditos se reservan.

from es el número que verá el destinatario. Con ak_test_ es nuestro número compartido y to tiene que ser uno de sus números de prueba verificados (si no, 409 test_destination_not_verified). Con ak_live_ es el suyo, y sin él listo la llamada no sale: 409 phone_number_required, 409 phone_number_in_review o 402 phone_number_suspended. Qué hacer en cada caso, en la página 14.

Si la conducta de pruebas transfiere a un número que ya no está verificado, la llamada sale sin transferencia y el acuse lo dice en warnings:

JSON
{ "…": "…", "warnings": { "ignored_variables": [], "transfer_disabled": { "reason": "test_destination_not_verified" } } }

Repetir la petición con la misma Idempotency-Key no repite el acuse. Mientras la llamada vive, su clave responde 409 request_in_flight, sin job_id, y su Retry-After es el tiempo máximo que le queda a la llamada (la duración autorizada que resta más un margen de cierre), no unos segundos. Cuando cuelga, devuelve el resultado guardado con el job_id original y los mismos warnings del acuse: call_id, status (completed), duration_seconds y billed_minutes. Cómo recuperar el job_id si perdió el acuse, en la página 17.

POST /v1/agent/turns · asíncrona

Un turno de conversación con su agente. Responde 202 con la ruta por la que se lee la respuesta mientras se genera.

CampoTipoObligatorioLímite
messagetextosí1–20.000 caracteres
channeltextosíuno de los canales admitidos
agent_idtextosíidentificador de un agente de su cuenta
conversation_external_idtextono1–128 caracteres
historylistanohasta 40 mensajes y 20.000 caracteres sumados
customerobjetonover abajo
variablesobjetonover contexto por petición
metadataobjetonoídem

Canales admitidos

Son estos nueve: whatsapp, facebook_messenger, instagram, telegram, email, sms, voice, chatbot_web y groups. Van en minúsculas y tal cual —WhatsApp no vale—, y cualquier valor fuera de esa lista recibe 400 validation_error con ella.

De dónde viene el mensaje es una declaración suya, no un canal que nosotros conectemos: no mandamos nada por él. Lo que hace es cambiar cómo se le habla al cliente final —un correo no se redacta como un mensaje de chat—, así que declare el real.

Cada mensaje de history lleva role (customer o agent), content y un timestamp opcional en ISO 8601. El rol es obligatorio: sin él, lo que dijo el agente se leería como algo que dijo el cliente y el modelo razonaría sobre una conversación que nunca ocurrió. El orden lo da la lista, no la fecha.

customer acepta external_id (1–128), name (1–200), phone (1–32) y email (1–320). Son datos suyos y opacos para nosotros: se le pasan al agente para que sepa con quién habla.

🔴 conversation_external_id y history son excluyentes. Dos fuentes para la misma conversación es una ambigüedad que nadie puede resolver bien, y la que perdiera se descartaría en silencio.

  • Con conversation_external_id: nosotros mantenemos la sesión. Usted manda solo el mensaje nuevo y la nombra con su identificador, así que el primer turno ya puede continuar una conversación sin una ida y vuelta previa. La clave es única por cuenta, así que nadie más ve la suya. La ventana vive 24 h de inactividad (página 13).
  • Con history: usted lleva la conversación y la envía en cada turno.
curl -sS -X POST "$ASIXTO_BASE_URL/v1/agent/turns" \
  -H "Authorization: Bearer $ASIXTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: turno-4471" \
  -d '{"message":"¿Cuál es el estado de mi pedido #12345?","channel":"whatsapp","agent_id":"a4f1c2e0-6d3b-4e7a-9c21-8f0e5b7d4a13","conversation_external_id":"cliente-12345"}'

Acuse: stream_id, status y stream_url. stream_url es la ruta por la que se lee la respuesta mientras se genera, y su contrato —eventos, forma de cada trama y reanudación— está en la página 19.

El turno se cobra por respuesta generada, con un precio único (página 12). Leer la respuesta no cuesta nada, ni la primera vez ni al reanudar: el cobro sigue a la generación, no a la entrega. Si su cliente se desconecta a mitad, el turno cuesta lo mismo.

El contexto por petición: variables y metadata

Las dos surten a POST /v1/calls y a POST /v1/agent/turns, con la MISMA forma y los mismos techos, y significan cosas opuestas:

variablesmetadata
¿La ve el agente?Sí: rellena los huecos de su configuración y las diceNo, nunca
¿Vuelve en el webhook?NoSí, en data.metadata
Para qué espersonalizar lo que se diceconciliar con su propio sistema

Los techos son los mismos para las dos: hasta 20 claves, cada clave en minúsculas, dígitos y _ empezando por letra y hasta 40 caracteres (loan_id, nombre_cliente), cada valor de hasta 512 caracteres y el objeto entero hasta 4 KB. Los valores van en texto, número o booleano —se guardan como texto— y no admiten objetos ni listas dentro: una clave anidada recibe 400 validation_error que la nombra, en vez de descartarse en silencio.

variables: los huecos de la configuración de su agente

En la consola, el saludo y el mensaje de apertura de un agente pueden llevar huecos con la forma {{clave}}. Lo que manda en variables es lo que los rellena, en esta petición y solo en esta:

JSON
{ "to": "+573001112233", "agent_id": "…", "variables": { "nombre_cliente": "Ana", "monto": "1.250.000" } }

Con el saludo Hola {{nombre_cliente}}, le llamo por su saldo de {{monto}}, el agente dice Hola Ana, le llamo por su saldo de 1.250.000.

Las dos reglas que le importan, y son opuestas a propósito:

  • 🔴 Falta una que el agente declara ⇒ 400 validation_error que la nombra. No se deja el hueco: un agente leyendo {{monto}} en voz alta a su cliente es peor que un rechazo que usted ve en su log.
  • Sobra una que ninguna plantilla usa ⇒ la petición SE ACEPTA y se lo decimos. La respuesta trae warnings.ignored_variables con esas claves. Es así porque el texto del agente se edita en la consola y no puede tumbarle su integración cada vez que alguien reescribe una frase — pero tampoco puede quedarse callado, o usted daría por hecho que su variable actuó.
JSON
{ "request_id": "req_…", "job_id": "job_…", "usage": { "…": "…" }, "result": { "…": "…" },
  "warnings": { "ignored_variables": ["descuento"] } }

warnings no viene si no hay nada que avisar: la clave está ausente, no vacía. Trate su presencia como la señal, no su contenido. Cuando viene, ignored_variables está siempre (vacía si no sobró ninguna) y, en POST /v1/calls, puede venir además transfer_disabled (ver la operación, arriba). Qué trae el replay de la clave depende de la superficie:

  • POST /v1/calls: los mismos warnings que el acuse original, porque se guardan con el trabajo al admitir la llamada.
  • Turno del agente: se recalculan con el agente tal como está al repetir. Con las mismas variables y el mismo texto del agente salen iguales; si alguien editó sus plantillas en la consola entre los dos intentos, ignored_variables puede cambiar.

metadata: sus identificadores, de ida y de vuelta

Es opaco para nosotros y para el agente: no entra en el prompt, el modelo no lo ve y nadie lo dice. Es el sitio de su loan_id, su case_id o su número de expediente. Vuelve tal cual en el webhook del cierre, dentro de data.metadata (página 11), y con eso cuadra el resultado contra su sistema sin guardar nuestro job_id en ningún sitio.

Vuelve también cuando el trabajo vence sin cierre (job.expired), que es justo el caso en el que le hace más falta.

Idempotencia: una clave identifica una operación, no una plantilla

Si repite una Idempotency-Key con otras variables, la petición se rechaza con 409 idempotency_key_reused en vez de devolverle el resultado de la primera. Reintentar la misma petición —mismas variables— sigue siendo idempotente y le devuelve el mismo trabajo. Cambiar solo el metadata no cuenta como otra operación: es un dato suyo de conciliación, no parte de lo que pidió.

Lo que el Gateway rellena y usted no puede escribir

En el turno, la identidad de su cuenta, la configuración del agente y la credencial con la que validamos las herramientas las pone el Gateway. Un cuerpo que intente escribir cualquiera de esas casillas se rechaza en vez de ignorarse: ignorarlo dejaría al integrador creyendo que configuró algo.

Elegir entre sus agentes es suyo. Configurarlos se hace en la consola, y es el producto.