Skip to main content

Relay a Face Detection

relay-ingest/face accepts one face detection from another site or system and records it on the receiving Identities server as a native detection. The body is the same WebHookFaceRecPayload that an Events Bridge face WebHook sends, so an Events Bridge can post here with no code. Any other client can build the same JSON.

Read the Relay Ingest Overview first for how the receiver identifies people, merges details and drops duplicates.

Quick Reference​

ItemValue
RequestPOST {baseUrl}/api/v1/relay-ingest/face, Content-Type: application/json
AuthHTTP Basic: username = Key ID, password = secret (from the receiver's admin)
Requiredpayload.detectionInfo.dateTimeUtc and payload.detectionImage.image
Makes it "known"Any of payload.personInfo names, tags, fields or notes
Success200 with an outcome. Every 200 is final.
RetryOnly 503 (honor Retry-After) and network failures, with the same detectId
Never retry200 and 403

API Endpoint​

  • HTTP Method: POST
  • Endpoint: /api/v1/relay-ingest/face
  • Base URL (Cloud): https://customername.econnectcloud.com/identities
  • Base URL (On-prem): https://<server-host-or-ip>:5009
  • Content-Type: application/json
  • Available from: Identities 0.23.0

The receiver's admin page shows the complete postback address when it creates the source's credentials.

Authentication​

Relay Ingest does not use the JWT from Authentication. Each sender has its own relay source credentials, created by an administrator of the receiving server under Setup → Integration → Relay Ingest:

CredentialFormatSent as
Key ID8 characters, A–Z and 2–7, for example ABCD2345. Public; matched case-insensitively.HTTP Basic username
Secret43 characters, base64url. Shown once; the receiver keeps only a SHA-256 hash.HTTP Basic password
Authorization: Basic <base64 of "KeyId:secret">

The credentials identify the sender. Nothing in the body is trusted for identity: sourceName, serverContext and externalId are informational only. If the secret is lost, the administrator rotates the key, which replaces both the Key ID and the secret and stops the old pair immediately.

A request is accepted only when the credentials are valid, the source is enabled, and the Relay Ingest module is enabled on the receiver. Every failure of these checks returns 403. This endpoint never returns 401.

Minimum Permission​

None. The source credentials replace user permissions on this endpoint. Creating sources and keys requires the Relay Ingest Administrator permission in the receiver's web app.

Request Body​

The envelope is an Events Bridge WebHookFaceRecPayload. Property names are matched case-insensitively, so both camelCase and PascalCase work. Images are base64 strings. Only payload is used. The envelope properties publishType, sourceName, externalId, fields and serverContext are accepted and ignored.

Requests are limited to 30 MB by default. A detection with two JPEG images is normally well under 1 MB.

Required Fields​

FieldTypeDescription
payload.detectionInfo.dateTimeUtcstring (ISO-8601)When the face was captured. Kept exactly. A value without a Z or an offset is read as UTC.
payload.detectionImage.imagestring (base64)The snapshot: a full frame or a generous crop (JPEG) that contains the face. Do not send a tightly cropped, aligned face. When the image holds several faces, the largest is the relayed one, and Face Recognition records the others as ordinary detections.

Detection Fields​

FieldTypeDescription
payload.detectionInfo.detectIdstringYour unique ID for this detection. Send the same value on every retry. A detectId received in the last hour is a Duplicate.
payload.detectionInfo.detectorNamestringThe camera name. Recorded as <camera prefix><detectorName>, for example Tahoe - Lobby. Defaults to Relay when empty. Also used by the duplicate rule.
payload.detectionInfo.timeZonestringIANA time zone. Accepted, but Face Recognition currently records the receiver's zone instead.
payload.detectionInfo.confidencenumberAccepted and ignored.
payload.defaultPhoto.imagestring (base64)Optional reference photo of the person. It is searched first when identifying the person, and enrolled when a new profile is created. Send a clear, frontal photo for known people when you have one.

Person Fields​

Any name, tag, field or note makes the detection known. With none of them it is unknown, and the receiver ignores it (IgnoredUnknown) unless the source is set to record unknown faces.

FieldTypeDescription
payload.personInfo.faceIdstringYour stable ID for this person's face. The receiver links it to its own face, so later detections skip the face search. It must be unique across every sender to the receiver: use a GUID. Used for known detections only.
payload.personInfo.firstNamestringFirst name.
payload.personInfo.middleNamestringMiddle name. Dropped if it equals lastName.
payload.personInfo.lastNamestringLast name.
payload.personInfo.tags[]object[]{ "tagName": string, "expires": ISO-8601 or null }. Tags are matched by name and created on the receiver when missing. expires is copied.
payload.personInfo.fields[]object[]{ "fieldName": string, "stringValue" | "boolValue" | "numberValue" | "dateValue" }. The first non-empty value in that order is used. Empty values are skipped. See Custom Fields.
payload.personInfo.notes[]object[]{ "noteTitle": string, "noteBody": string }. Notes titled eConnect Sync Notes or eConnect Shared Sync Notes are never relayed.

How these values change a person the receiver already has depends on the source's merge rules. A person the relay creates always receives all of them.

Ignored Fields​

payload.detectionHistory, payload.resentEvent and payload.messageId are accepted and ignored. Deduplication uses detectId, not messageId.

Custom Fields​

fieldName is matched to one of the receiver's custom fields, in this order:

  1. the source's field map, maintained by the receiver's administrator;
  2. a receiver field with the same ID, such as the built-in MOBILE_PHONE_NUMBER, PHONE_NUMBER, EMAIL, EMPLOYEE_ID or LOYALTY_CARD;
  3. a receiver field whose friendly name equals fieldName, ignoring case, for example "Member Number".

A field that matches nothing is skipped, and the receiver never creates fields. The receiver's admin page lists unmatched field names with a sample value so that they can be mapped.

Writing your own sender

If you control the sender, use the receiver's built-in field IDs or its friendly field names as fieldName. They match without any field map.

Minimal Example​

This detection is unknown (no person details). It is recorded only if the source records unknown faces. Otherwise the response is IgnoredUnknown.

{
"payload": {
"detectionInfo": {
"dateTimeUtc": "2026-10-02T17:04:22.918Z",
"detectId": "3b8e2f61-7c4a-4d19-a2b5-90e6f1c7d842",
"detectorName": "Lobby"
},
"detectionImage": { "image": "/9j/4AAQSkZJRgABAQEASABIAAD..." }
}
}

Full Example​

A known detection with every field Relay Ingest uses:

{
"publishType": "WebHookFaceRecPayload",
"sourceName": "Tahoe Identities",
"payload": {
"personInfo": {
"faceId": "6f1c2a9e-4b7d-4f3a-9c2e-1d5b8a7f0e34",
"firstName": "Jane",
"middleName": "",
"lastName": "Smith",
"tags": [
{ "tagName": "VIP", "expires": null }
],
"fields": [
{ "fieldName": "EMAIL", "stringValue": "jane.smith@example.com" },
{ "fieldName": "Member Number", "stringValue": "100245" }
],
"notes": [
{ "noteTitle": "Host", "noteBody": "Prefers the north entrance." }
]
},
"detectionInfo": {
"dateTimeUtc": "2026-10-02T17:04:22.918Z",
"timeZone": "America/Los_Angeles",
"confidence": 0.97,
"detectId": "3b8e2f61-7c4a-4d19-a2b5-90e6f1c7d842",
"detectorName": "Lobby"
},
"detectionImage": { "image": "/9j/4AAQSkZJRgABAQEASABIAAD..." },
"defaultPhoto": { "image": "/9j/4AAQSkZJRgABAQEASABIAAD..." }
}
}

Raw Request​

POST https://customername.econnectcloud.com/identities/api/v1/relay-ingest/face
Authorization: Basic QUJDRDIzNDU6eW91cl80M19jaGFyYWN0ZXJfc2VjcmV0
Content-Type: application/json

{ "payload": { ... } }

The header above encodes the placeholder pair ABCD2345:your_43_character_secret.

Code Examples​

API_URL="https://customername.econnectcloud.com/identities"
KEY_ID="ABCD2345" # Basic Auth username (Key ID)
SECRET="your_43_character_secret" # Basic Auth password (secret)

# A full snapshot (not a tight crop) that contains the face.
IMAGE_B64=$(base64 -w 0 snapshot.jpg)

# Write the body to a file: base64 images are too large for a command-line argument.
cat > relay-body.json <<EOF
{
"payload": {
"personInfo": {
"faceId": "6f1c2a9e-4b7d-4f3a-9c2e-1d5b8a7f0e34",
"firstName": "Jane",
"lastName": "Smith",
"tags": [ { "tagName": "VIP" } ]
},
"detectionInfo": {
"dateTimeUtc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"timeZone": "America/Los_Angeles",
"detectId": "$(uuidgen)",
"detectorName": "Lobby"
},
"detectionImage": { "image": "$IMAGE_B64" }
}
}
EOF

# 200 = processed (read "outcome"), 403 = fix credentials or configuration, 503 = retry later.
curl -s -X POST "$API_URL/api/v1/relay-ingest/face" \
-u "$KEY_ID:$SECRET" \
-H "Content-Type: application/json" \
--data-binary @relay-body.json \
-w "\nHTTP %{http_code}\n"

Replace the placeholders (base URL, Key ID, secret and image files) with your own values.

Response​

Every processed detection returns 200 OK with this body:

{
"outcome": "Recorded",
"reason": null,
"localFaceId": "8d2f4c1a-93b7-4e05-b6a1-2c7e9f0d3a58",
"detectId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
FieldTypeDescription
outcomestringWhat happened. See Outcomes.
reasonstring or nullA machine-readable detail. Several reasons are joined with ; .
localFaceIdstring or nullThe receiver's face the detection was recorded on (Recorded), or the expected face (Duplicate, when one was found).
detectIdstring or nullThe receiver's own ID for the recorded detection. Set for Recorded only. It is not your detectId.

Outcomes​

Every outcome is final. Do not retry any 200.

outcomereason valuesMeaning
Recordednull, MatchedAnotherFace, MergeErrors:NStored, shown on the Live Monitor and published. MatchedAnotherFace: Face Recognition filed it under a different face than the expected person's. MergeErrors:N: N details could not be applied to the person. The detection is still recorded.
DuplicateAlreadyRecordedAlready recorded: a retry, a second route or a loop.
IgnoredUnknownUnknownFaceNo person details, and the source ignores unknown faces.
RejectedInvalidMissingPayload, MissingCaptureTime, MissingDetectionImage, MalformedJsonThe body is incomplete or not JSON. Fix the sender: the same body never succeeds.
RejectedNoFaceNoFaceInPhoto, NoFaceInDetectionImageNo face was found in the photo used to create the person, or in the snapshot.

Response Codes​

CodeBodyMeaningSender action
200 OKThe response aboveProcessed. Read outcome.Done. Never retry.
403 Forbidden{ "reason": "Forbidden" }The Authorization header is missing or malformed, the Key ID is unknown, the secret is wrong, or the source is disabled.Do not retry. Fix the credentials or ask the receiver's admin to enable the source.
403 Forbidden{ "reason": "RelayIngestDisabled" }The Relay Ingest module is switched off on the receiver.Do not retry. Ask the receiver's admin.
503 Service Unavailable{ "reason": "Busy" }The receiver is already processing its maximum number of detections.Retry after the Retry-After delay (5 seconds).
503 Service Unavailable{ "reason": "Timeout" } or { "reason": "Unavailable" }Processing ran out of time, or Face Recognition or the database failed.Retry with backoff, using the same detectId.
503 Service Unavailable{ "reason": "RecordingDisabled" }Detection recording is switched off on the receiver.Keep the detection and retry later.

Events Bridge follows these rules on its own: it drops a 403 without retrying, and retries other failures according to the WebHook's retry settings.

Sending Reliably​

  • Retry only 503 and network failures, with exponential backoff, and honor Retry-After.
  • Keep detectId and dateTimeUtc identical on every attempt. If an earlier attempt succeeded but its response was lost, the retry comes back as Duplicate instead of creating a second detection.
  • Use a client timeout of at least 60 seconds. The receiver allows itself 30 seconds per detection.
  • Send one at a time, or only a few in parallel. The receiver processes 4 detections at once by default.
  • Use HTTPS with a certificate the client validates. HTTP Basic credentials are only as safe as the connection that carries them.