❮  Integraciones

API para empresas

Su cliente concede acceso a su empresa y en su aplicación aparece un botón Abrir. Ninguna llave circula por chats y cada apertura lleva el nombre del empleado que la pulsó.

Para quién: servicios cuyo empleado debe entrar en un patio cerrado — niñeras y profesores, limpieza, taller móvil de neumáticos y lavado, mensajería y reparto, enfermería y analíticas a domicilio. El cliente conserva la barrera que ya tiene; usted gana un botón en vez de una llamada al cliente en la puerta.

Cómo funciona

  1. En su interfaz el cliente indica que hay que entrar. Antes comprueba dos cosas: la barrera se abre con una llamada desde su número y su teléfono sigue en línea. Si la barrera tiene un controlador Entrixy, el teléfono no hace falta.
  2. Usted crea una solicitud y muestra su código QR. El cliente lo escanea, instala la aplicación, añade la barrera y concede el acceso: su empresa ya espera en la lista.
  3. Usted abre por API nombrando al empleado. El cliente ve la apertura en el registro con ese nombre y retira el acceso con un toque cuando quiera.
La llave no existe como enlace. Su empresa recibe una referencia a ella, no la llave misma: no hay nada que copiar ni reenviar; la llave está ligada a su cuenta y funciona solo por esta API. Pasar el acceso a un empleado no es posible, y es a propósito: por eso el cliente lo concede tranquilo.

Autenticación

There are two ways in, and the difference is what the client sees.

Signature bound to your domain

You publish a public key on your own domain and sign every call with the private one. We take the key from the domain itself, so the right to call and the right to be shown under that domain are the same thing: the file disappears, the domain moves or changes hands — the calls stop at once. There is no one-off "verified" tick to outlive reality.

https://<your domain>/.well-known/entrixy.json

{ "key": "<Ed25519 public key, 32 bytes, base64>" }

El par se crea en tu lado; la mitad privada no la vemos nunca. Bastan dos órdenes:

openssl genpkey -algorithm ed25519 -out entrixy-private.pem
openssl pkey -in entrixy-private.pem -pubout -outform DER | tail -c 32 | base64

La segunda imprime la cadena para el archivo. La primera deja la clave privada contigo: firma cada llamada y no hay adónde enviarla.

Then each request carries four headers:

X-Entrixy-Org:   your-domain.com
X-Entrixy-Ts:    1750000000          // unix seconds, ±300 s
X-Entrixy-Nonce: 0011…ff             // 32 lowercase hex characters, used once
X-Entrixy-Sig:   <base64>            // Ed25519 over the base string

base = "<domain>.<ts>.<nonce>." + sha256(raw request body)

A repeated nonce is refused, and so is a body that does not match the signature. This is the mode where the client sees your domain and your logo.

A domain written in national characters goes into the header and into the base string in its punycode form — xn--… — the same form it takes in the address of the key file. The client is still shown the readable spelling.

Signing in PHP, for example. openssl leaves a PEM file with a 32-byte seed, while sodium signs with the 64-byte secret key, so the first three lines derive one from the other:

$pem   = file_get_contents('entrixy-private.pem');
$der   = base64_decode(preg_replace('/-----[^-]+-----|\s+/', '', $pem));
$secretKey = sodium_crypto_sign_secretkey(sodium_crypto_sign_seed_keypair(substr($der, -32)));

$body  = json_encode($payload, JSON_UNESCAPED_UNICODE);
$ts    = time();
$nonce = bin2hex(random_bytes(16));      // 32 lowercase hex characters
$base  = "$domain.$ts.$nonce." . hash('sha256', $body);
$sig   = base64_encode(sodium_crypto_sign_detached($base, $secretKey));

Send the body exactly as it was signed, byte for byte, together with the four headers.

A call is refused before any action when the authentication does not pass:

RespuestaMeaning
401 authunknown company or a wrong secret
401 stale_timestampthe time in the header differs from ours by more than 300 seconds
401 bad_noncethe nonce is not 32 hex characters
401 replaythis nonce has already been used
401 bad_signaturethe signature does not match the body
401 domain_key_unavailablethe key file could not be fetched from your domain
401 sign_requiredyour domain already has a key, so a secret is no longer accepted
403 org_blockedthe company is blocked

A secret, if you have no domain

Register, issue a secret in the cabinet and put it in the body together with your company number. A secret is enough to create requests and to read their state and contents: a=request, a=status and a=objects. The client then sees only your name with a note that the domain is not confirmed — no logo, no domain.

Opening needs the domain signature. The client’s phone checks every opening of a company with the key from its domain, so a=open with a secret alone answers 401 sign_required. As soon as the key appears on your domain the secret stops working for every call: otherwise a leaked secret would speak in the name of a confirmed company.

POST https://entrixy.com/api/company.php?a=<action>
Content-Type: application/json

{ "org_id": 17, "secret": "…", … }

The examples below show the secret in the body for brevity. With the signature the same body goes without org_id and secret, and the four headers are added.

Crear una solicitud

POST /api/company.php?a=request
{ "org_id": 17, "secret": "…", "ref": "order-517", "ttl_hours": 72 }

→ { "code": "rrGzNweV31rkHV6Q",
    "url":  "https://entrixy.com/c/rrGzNweV31rkHV6Q",
    "expires_in_hours": 72 }

ref es su propio número de pedido, vuelve en el estado. Ponga url en un código QR y muéstrelo al cliente.

Estado de la solicitud

POST /api/company.php?a=status
{ "org_id": 17, "secret": "…", "code": "rrGzNweV31rkHV6Q" }

→ { "state": "issued", "key_ref": 4821, "ref": "order-517",
    "claimed_at": "2026-09-09 12:20:11", "issued_at": "2026-09-09 12:24:03" }
EstadoMeaning
newel código QR está creado, el cliente aún no ha llegado
claimedel cliente abrió la aplicación: está en camino
issuedacceso concedido; key_ref con eso abre
revokedel cliente retiró el acceso
caducadola solicitud caducó antes de que llegara el cliente

Qué abre la llave

The answer to a=status already carries the contents of the key, and the same list comes from a=objects — by key_ref or by the request code.

POST /api/company.php?a=objects
{ "org_id": 17, "secret": "…", "key_ref": 96 }

{
  "key_ref": 96,
  "numbers": [
    { "number_id": 83, "name": "Шлагбаум во двор", "type": "call", "openable": true },
    { "number_id": 84, "name": "Ворота на парковку", "type": "call", "openable": true }
  ]
}

number_id is what you pass to a=open; it belongs to the object and does not change when the client renames it. name is the name the client gave the object and agreed to show you — the client's own names are encrypted and we do not see them, so this one arrives only because the client sent it along with the access. Until an older app is updated the field comes as null: show the visit address instead. openable is false for an object that only its holder can open — a call from the company will be refused.

When a key covers a single object, number_id en a=open may be omitted.

Apertura

POST /api/company.php?a=open
Content-Type: application/json
X-Entrixy-Org:   your-domain.com
X-Entrixy-Ts:    1750000000
X-Entrixy-Nonce: 9f86d081884c7d659a2feaa0c55ad015
X-Entrixy-Sig:   <base64>

{ "key_ref": 4821, "number_id": 93, "actor": "Ivan P., shift 12" }

→ { "ok": 1 }

actor es obligatorio: es lo que el cliente ve en el registro. Sirve cualquier cosa que identifique al empleado — nombre, número de ficha, turno. Sin él la llamada se rechaza.

RespuestaMeaning
401 sign_requiredthe call is not signed with the domain key: a secret is not enough to open
400 bad_inputkey_ref is missing
400 number_id_requiredthe key covers several objects and the object was not named
400 actor_requiredno se ha nombrado al empleado
400 unsupported_objectthis object cannot be opened by a company: its openable is false
403 revokedthe client took the access back, the key is not yours, or the object is not in it
403 expiredla vida de la llave ha terminado
429 rate_limitdemasiadas aperturas con una llave por minuto

The authentication answers from the table above apply here too.

Su ficha en la aplicación

Al registrar la empresa, envíenos el nombre y un logotipo cuadrado. El cliente los ve en la página que escanea, en la pantalla de consentimiento y junto a cada línea del registro, así sabe a quién deja entrar. El logotipo lo servimos nosotros; no traemos imágenes de otros servidores.

Cuando el cliente retira el acceso

The client removes the company in their app — the key disappears at once. a=open answers revoked, a=objects the same, and a=status shows the request as revoked with an empty list of objects. Nothing else has to be done on your side: a revoked access never comes back, a new visit needs a new request.

If you saved a callback address, we also ping it on the events — claimed, issued, revoked:

POST <your callback address>
{ "event": "revoked", "org_id": 5, "code": "eAc9SZ8mmeegD_GJ", "key_ref": 96 }

The address must start with https. The ping waits 3 seconds for an answer and does not follow redirects.

The ping is a nudge, not the source of truth: it carries no object list and is sent once, without retries. Take the details from a=status — that call is signed and answers the same thing whether the ping arrived or not.

Primeros pasos

Registra la empresa en tu cuenta: es un solo formulario y empieza a funcionar de inmediato. El dominio, el secreto, la dirección de callback, el logotipo y la lista de solicitudes están en el área de la empresa.

Panel de la empresa