---
title: Testing & Deployment
slug: frameworks/xtwe-aci
createdAt: 2026-05-26T06:23:04.000Z
---

# Integration Registration and Configuration

ACI integrations are set up by a Sine team member in the Sine platform on your behalf. You do not configure the integration directly - instead, you provide your endpoint URLs and API key to your Sine contact, who will configure and test the integration in a Sine environment for you.

## What to Prepare

Before your setup session with Sine, have the following ready:

| Item                  | Description                                                                                                                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Endpoint URLs**     | HTTPS URLs for your Verify, Provision, Activate, and Deprovision endpoints. These must be internet-accessible from Sine's cloud. For local development, use a tunnelling tool such as ngrok. |
| **API key**           | A secret key your endpoint will use to authenticate incoming requests from Sine. You generate this on your side. Sine sends it as the `Authorization` header on every request.               |
| **Access Groups URL** | Optional. The HTTPS URL for your Access Groups endpoint, if supported.                                                                                                                       |
| **Credential type**   | Whether your integration supports `digital`, `physical`, or `virtual` credentials.                                                                                                           |
| **External ID**       | Optional. A reference string your integration can use to identify the site or configuration context. Sine includes this in every request body if configured.                                 |

## Configuration Reference

The following fields are configured in Sine during setup. Understanding what each field does is important because they directly affect the requests your integration receives.

### Endpoint URLs

| Setting                | Required | Effect                                                     |
| ---------------------- | -------- | ---------------------------------------------------------- |
| Verify endpoint        | Yes      | Called during setup and connectivity checks.               |
| Provision endpoint     | Yes      | Called on visitor check-in.                                |
| Activate endpoint      | Yes      | Called after approval checks complete.                     |
| Deprovision endpoint   | Yes      | Called on check-out or visit expiry.                       |
| Access Groups endpoint | No       | Enables access group selection in Sine's configuration UI. |

### Credential Behaviour

| Setting                      | Required | Effect on your integration                                                                                                                   |
| ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Credential type**          | Yes      | Determines whether Sine sends a `badgeNumber` (physical) or expects a generated `barcode` in the Provision response (digital/virtual).       |
| **Provision on check-in**    | Yes      | Controls which visitor types trigger a Provision call.                                                                                       |
| **Deprovision on check-out** | No       | When enabled for a visitor type, Sine calls Deprovision on checkout. Also causes `checkoutUrl` to be included in the Provision request body. |
| **Grace period**             | No       | Extends `validTo` beyond the pass end time by a configured number of minutes. Your ACS should honour the `validTo` value in the request.     |

### Failure Handling

| Setting                             | Effect                                               |
| ----------------------------------- | ---------------------------------------------------- |
| **Visitor failure message**         | Displayed to the visitor in Sine if Provision fails. |
| **Failure notification email list** | Email addresses notified when lifecycle calls fail.  |

### Optional Features

| Setting            | Effect                                                                                                                                                    |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **External ID**    | A free-text string (max 256 characters) sent in every request body. Useful for mapping a Sine site to a reference in your own system.                     |
| **Send QR by SMS** | When enabled, Sine sends the provisioned QR credential to the visitor's mobile number via SMS. No change to your endpoint contract.                       |
| **Secure Bridge**  | An alternative to public endpoints. Routes Sine requests through an encrypted tunnel to your local network. Contact your Sine representative for details. |

## How Sine Authenticates to Your Endpoint

Sine sends your configured API key as the `Authorization` header on every lifecycle request:

```javascript
Authorization: <your-api-key>
```

Your endpoint must validate this header on every request and return `401` if it is absent or does not match.

:::BlockQuote
**Security note:** Treat this API key as a secret. Do not log it, commit it to version control, or embed it in client-side code. Store it using your platform's secret management tooling (environment variables, a secrets manager, or equivalent).
:::

## Branded Integrations

If your integration is intended for distribution - for use by multiple Sine customers rather than a single site - Sine can brand it under your company or product name. Branded integrations appear in the Sine integrations list under your name rather than as a generic "Access Control" configuration.

To set up a branded integration, provide your Sine representative with the following:

| Item                   | Details                                                                                                                                                                                                                                              |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Integration name**   | Your preferred display name as it should appear in the Sine integrations list.                                                                                                                                                                       |
| **Icon**               | A 256×256 PNG image. Used as the integration's logo in the Sine interface.                                                                                                                                                                           |
| **Endpoint URLs**      | The specific URL for each required endpoint (Verify, Provision, Activate, Deprovision) and optionally Access Groups.                                                                                                                                 |
| **Regional endpoints** | If your platform operates across multiple regions (for example, a US domain and an EU domain), provide the endpoint URLs for each region. Sine will configure region-specific variants so that customer data stays within the appropriate geography. |

Contact your Sine representative to discuss the requirements and process for a branded integration.

# Testing Your Integration

Testing an ACI integration has two distinct phases: testing your endpoint directly (before Sine is involved) and testing the full end-to-end flow through a Sine test environment.

## Testing with a Sine Test Environment

Once your Sine contact has configured the integration in a test environment, you can trigger the full lifecycle by performing a real check-in and check-out through Sine.

**What to test:**

| Scenario                        | How to trigger                                            | What to verify                                                                                               |
| ------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Provision called on check-in    | Check a visitor in at the configured site                 | Endpoint receives Provision request; returns `PROVISIONED` with correct `barcode` and `accessControlVisitId` |
| Activate called after check-in  | Check in completes (Activate is automatic)                | Endpoint receives Activate with the `badgeNumber` from Provision response; returns `ACTIVATED`               |
| Deprovision called on check-out | Check the visitor out                                     | Endpoint receives Deprovision; credential is revoked in ACS                                                  |
| Deactivate-only mode            | Check out with `deactivateOnly` configured                | Endpoint receives `?deactivateOnly=true`; credential is disabled but not deleted                             |
| ACS-initiated checkout          | Configure exit reader callback; visitor badges out        | ACS posts to `checkoutUrl`; Sine checks visitor out and calls Deprovision                                    |
| Verify                          | Use the test/verify action in Sine's integration settings | Endpoint receives Verify; returns `SUCCESS`                                                                  |

**Recommended check-in path for testing:**

1. In your Sine test environment, go to **Locations** → select your site → **Integrations** → open the configured Access Control integration.
2. Use the **Test** or **Verify** button to confirm connectivity before performing a full check-in.
3. Check in a test visitor. Watch your endpoint logs for the incoming Provision request.
4. Confirm the credential was created in your ACS in an inactive state.
5. Confirm the Activate request arrives shortly after, and access is enabled.
6. Check out the visitor. Confirm Deprovision fires and the credential is revoked in your ACS.

**Tips:**

- Use a tool like ngrok to expose a local endpoint during development. Your Sine contact can configure the integration to point to your ngrok URL.
- Log the full request body (excluding the `Authorization` header value) on every incoming request - this makes debugging lifecycle issues significantly easier.
- Test idempotency: call each endpoint twice with the same payload and confirm the second call returns the correct success response without creating duplicate records.

## Sending Mock Requests Directly

You can test your endpoint contract without a Sine environment by sending HTTP requests directly. This is useful for verifying your request parsing, authentication checks, and response shapes early in development.

The examples below use `curl`. Replace `https://your-endpoint.example.com` with your actual URL and `your-api-key` with the key you have configured.

### Verify

```bash
curl -X POST https://your-endpoint.example.com/verify \
  -H "Authorization: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"externalId": "test-site"}'
```

Expected response:

```json
{ "code": "SUCCESS" }
```

### Provision (digital credential)

```bash
curl -X POST https://your-endpoint.example.com/provision \
  -H "Authorization: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "visitId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "siteId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "credentialType": "digital",
    "validFrom": "2026-05-26T09:00:00.000Z",
    "validTo": "2026-05-26T17:00:00.000Z",
    "visitor": {
      "firstName": "Test",
      "lastName": "Visitor",
      "email": "test@example.com"
    }
  }'
```

Expected response:

```json
{
  "code": "PROVISIONED",
  "data": {
    "barcode": "<unpredictable-credential-value>",
    "accessControlVisitId": "<your-acs-holder-id>"
  }
}
```

### Activate

```bash
curl -X POST https://your-endpoint.example.com/activate \
  -H "Authorization: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "visitId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "siteId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "credentialType": "digital",
    "accessControlVisitId": "<value-from-provision-response>",
    "badgeNumber": "<barcode-from-provision-response>"
  }'
```

Expected response:

```json
{ "code": "ACTIVATED" }
```

### Deprovision

```bash
curl -X POST https://your-endpoint.example.com/deprovision \
  -H "Authorization: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "visitId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "siteId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "credentialType": "digital",
    "accessControlVisitId": "<value-from-provision-response>",
    "badgeNumber": "<barcode-from-provision-response>"
  }'
```

Expected response:

```json
{ "code": "DEPROVISIONED" }
```

### Testing authentication rejection

Confirm your endpoint returns `401` for a missing or invalid API key:

```bash
curl -X POST https://your-endpoint.example.com/verify \
  -H "Authorization: wrong-key" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Expected response: HTTP `401` with a structured error body.

## Validation Checklist

Use this checklist before going live or handing off to your Sine contact for integration testing.

### Authentication

- [ ] Endpoint returns `401` for missing `Authorization` header
- [ ] Endpoint returns `401` for an incorrect API key
- [ ] API key is stored securely and not logged or committed to version control

### Verify

- [ ] Returns `{ "code": "SUCCESS" }` with HTTP `200`
- [ ] Completes quickly (under 2 seconds)

### Provision

- [ ] Returns `{ "code": "PROVISIONED", "data": { ... } }` with HTTP `201`
- [ ] `data.barcode` is present and non-empty
- [ ] `data.accessControlVisitId` is present and non-empty
- [ ] For digital credentials: `barcode` is unpredictable (non-sequential, non-guessable)
- [ ] For physical credentials: `barcode` echoes the `badgeNumber` sent in the request
- [ ] Credential is created in ACS in an **inactive/disabled state** (does not grant access yet)
- [ ] Calling Provision twice with the same `visitId` returns `PROVISIONED` without creating duplicates
- [ ] Response time is consistently under 5 seconds (blocking check-in path)

### Activate

- [ ] Returns `{ "code": "ACTIVATED" }` with HTTP `200`
- [ ] Credential in ACS grants access after Activate is called
- [ ] Calling Activate twice with the same identifiers returns `ACTIVATED` (idempotent)

### Deprovision

- [ ] Returns `{ "code": "DEPROVISIONED" }` with HTTP `200`
- [ ] Credential in ACS no longer grants access after Deprovision
- [ ] Calling Deprovision twice with the same identifiers returns `DEPROVISIONED` (idempotent)
- [ ] `deactivateOnly=true` disables access without hard-deleting ACS records (if supported)

### Error handling

- [ ] Invalid or missing required fields return `400` with a structured error body
- [ ] Downstream ACS unavailability returns `5xx` (not a silent success)
- [ ] Error response body follows `{ "code": "REQUEST_FAILED_ERROR", "message": "..." }` shape
- [ ] Error messages are actionable - they describe what failed and whether a retry is likely to help

### Access Groups (if implementing)

- [ ] `/access-groups` returns `{ "results": [...] }` with HTTP `200`
- [ ] Each result includes `id` and `name`
- [ ] `nameIncludes` filtering works case-insensitively (or returns full list if filtering unsupported)
- [ ] `nextLink` is included when more results exist and is directly callable

***

#
