Manages enterprise template and logging operations.
This module provides functions for card template management (create, update, read), retrieving activity logs, and listing template pairs. These are enterprise-only features requiring special account permissions.
Examples
# Create a new template
{:ok, result} = AccessGrid.Console.create_template(%{
name: "Employee Badge",
platform: "apple",
use_case: "employee_badge",
protocol: "desfire"
})
# Read full template details
{:ok, template} = AccessGrid.Console.read_template(result.id)
# Get activity logs
{:ok, logs, pagination} = AccessGrid.Console.get_logs(template.id)
Summary
Functions
Completes registration for an HID Origo organization (activate).
Creates a card template pair from an existing Apple and Google template.
Creates a new credential profile.
Registers a new HID Origo organization for the account.
Creates a new landing page.
Creates a new card template.
Creates a new webhook subscription.
Deletes a webhook subscription.
Retrieves activity logs for a card template.
Runs Apple Wallet In-App Provisioning preflight for an access pass.
Lists all pass template pairs for the account.
Lists all credential profiles for the account.
Lists HID Origo organizations registered to the account.
Lists all landing pages for the account.
Lists ledger items for the account, paginated and optionally date-filtered.
Lists webhook subscriptions for the account.
Publishes a card template, moving it out of draft toward ready or in-review.
Retrieves a card template or card template pair by id.
Reveals Smart Tap credentials for a card template, encrypted with the caller's ephemeral public key.
Updates an existing landing page.
Updates an existing card template.
Types
@type credential_profile_result() :: {:ok, AccessGrid.CredentialProfile.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type credential_profiles_result() :: {:ok, [AccessGrid.CredentialProfile.t()]} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type hid_org_result() :: {:ok, AccessGrid.HidOrg.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type hid_orgs_result() :: {:ok, [AccessGrid.HidOrg.t()]} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type ios_preflight_result() :: {:ok, AccessGrid.IosPreflight.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type landing_page_result() :: {:ok, AccessGrid.LandingPage.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type landing_pages_result() :: {:ok, [AccessGrid.LandingPage.t()]} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type ledger_items_result() :: {:ok, [AccessGrid.LedgerItem.t()], map()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type logs_result() :: {:ok, [AccessGrid.Event.t()], map()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type pair_summary_result() :: {:ok, AccessGrid.CardTemplatePair.Summary.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type pairs_result() :: {:ok, [AccessGrid.CardTemplatePair.Summary.t()], map()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type publish_result() :: {:ok, AccessGrid.CardTemplate.PublishResult.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type result() :: {:ok, AccessGrid.CardTemplate.Result.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type smart_tap_reveal_result() :: {:ok, AccessGrid.SmartTapReveal.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type template_result() :: {:ok, AccessGrid.CardTemplate.t() | AccessGrid.CardTemplatePair.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type webhook_delete_result() :: :ok | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type webhook_result() :: {:ok, AccessGrid.Webhook.t()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
@type webhooks_result() :: {:ok, [AccessGrid.Webhook.t()], map()} | {:error, AccessGrid.Types.api_error_reason(), AccessGrid.HttpFailure.t() | [atom(), ...]}
Functions
@spec activate_hid_org( map(), keyword() ) :: hid_org_result()
Completes registration for an HID Origo organization (activate).
Rails may return extra fields on the response (already_completed: true when
the org is already activated, job_queued: true when a registration job is
in flight). Those flags are not surfaced on the returned struct — inspect
org.status to determine activation state.
Parameters
params- Map with::email- Email used to register the org:password- HID portal password
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %HidOrg{}}- 200 OK (fresh, already-complete, or no-op){:error, reason, %HttpFailure{}}- 404 if no org matches the email
@spec create_card_template_pair( map(), keyword() ) :: pair_summary_result()
Creates a card template pair from an existing Apple and Google template.
The Rails API enforces several validations before the pair is created:
- Both referenced templates must belong to the current account (404 otherwise).
- Apple template must have
platform == "apple"and Google templateplatform == "android"(422). - Protocol combination must be either both SEOS, or Apple DESFire + Google Smart Tap (422).
- Both templates must be in
status == "ready"(i.e. published) (422).
Parameters
params- Map with::name- Name for the new pair (required):apple_card_template_id- ex_id of the published Apple template:google_card_template_id- ex_id of the published Google template
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CardTemplatePair.Summary{}}- Pair created. Same shape as items returned bylist_card_template_pairs/1.{:error, reason, %HttpFailure{}}- Creation failed.
@spec create_credential_profile( map(), keyword() ) :: credential_profile_result()
Creates a new credential profile.
Parameters
params- Map with::name- Display name (required):app_name- Reader app name (optional, defaults to"KEY-ID-main"):keys- List of%{value, keys_diversified?, source_key_index?}maps; length must match the app's required key count:file_id- Hex file id string (optional, defaults to"00")
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CredentialProfile{}}- Created{:error, reason, %HttpFailure{}}- 422 on invalidapp_name, wrong key count, or validation failure
@spec create_hid_org( map(), keyword() ) :: hid_org_result()
Registers a new HID Origo organization for the account.
Idempotent on name → slug: if an org with the derived slug already exists,
Rails returns the existing record with status 200 instead of creating a new one.
Parameters
params- Map with::name- Display name (required):full_address- Full mailing address:phone- Contact phone number:first_name- Primary contact first name:last_name- Primary contact last name
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %HidOrg{}}- Created (201) or existing (200){:error, reason, %HttpFailure{}}- 422 on validation failure
@spec create_landing_page( map(), keyword() ) :: landing_page_result()
Creates a new landing page.
Parameters
params- Map with::name- Display name (required):kind- Landing page kind (required; immutable after creation):additional_text,:bg_color,:allow_immediate_download,:password,:is_2fa_enabled- Optional fields:logo- Base64-encoded PNG or JPEG image (optional)
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %LandingPage{}}- Created{:error, reason, %HttpFailure{}}- Creation failed
Creates a new card template.
Params are passed straight through to Rails — pass top-level keys using the
exact wire names (no nested design: / support_info: wrappers). Image fields
(background, logo, icon) accept base64-encoded strings; see
AccessGrid.Utils.base64_file/1 for a helper.
Parameters
params- Template configuration::name- Display name for the template (required):platform-"apple"or"android"(required):use_case- e.g."employee_badge"(required):protocol-"desfire"(Apple),"seos", or"smart_tap"(Android):allow_on_multiple_devices,:watch_count,:iphone_count- Device limits:background_color,:label_color,:label_secondary_color- Style settings:background,:logo,:icon- Base64-encoded PNG/JPEG images (max 10MB decoded):support_url,:support_phone_number,:support_email- Support contact info:privacy_policy_url,:terms_and_conditions_url- Legal URLs:credential_profiles- List of credential-profile ex_id strings to attach:landing_pages- List of landing-page ex_id strings to attach:metadata- Custom metadata map
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CardTemplate.Result{}}- Template created successfully{:error, reason, %HttpFailure{}}- Creation failed
@spec create_webhook( map(), keyword() ) :: webhook_result()
Creates a new webhook subscription.
Parameters
params- Map with::name- Display name:url- HTTPS endpoint to receive events:subscribed_events- List of event names (e.g.["ag.access_pass.issued"]):auth_method-"bearer_token"(default) or"mtls"
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %Webhook{}}- Created. Forbearer_token, the struct includesprivate_key(sensitive — store on receipt, Rails does not return it again). Formtls, the struct includesclient_certandcert_expires_at.{:error, reason, %HttpFailure{}}- 422 on empty or invalidsubscribed_events.
@spec delete_webhook( String.t(), keyword() ) :: webhook_delete_result()
Deletes a webhook subscription.
Parameters
webhook_id- The webhook ID to deleteopts- Options::client- Client struct (optional, defaults to config)
Returns
:ok- Deleted (Rails returns 204 No Content; there is no body){:error, reason, %HttpFailure{}}- 404 if id missing
@spec get_logs( String.t(), keyword() ) :: logs_result()
Retrieves activity logs for a card template.
Parameters
template_id- The template ID to get logs foropts- Options::client- Client struct (optional, defaults to config):page- Page number (default: 1):per_page- Results per page (default: 50, max: 100):filters- Map with optional filters::device- "mobile" or "watch":start_date- ISO8601 timestamp:end_date- ISO8601 timestamp:event_type- Event type string
Returns
{:ok, [%Event{}], pagination}- List of events and pagination info{:error, reason, %HttpFailure{}}- Retrieval failed
@spec ios_preflight(String.t(), map(), keyword()) :: ios_preflight_result()
Runs Apple Wallet In-App Provisioning preflight for an access pass.
Returns the identifiers needed to drive the iOS provisioning flow. Note that Rails returns these keys in camelCase (Apple convention); the resulting struct uses snake_case Elixir-idiomatic field names.
Parameters
template_id- The card template ID containing the access passparams- Map with::access_pass_ex_id- ex_id of the access pass to preflight (required)
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %IosPreflight{}}- Preflight identifiers{:error, reason, %HttpFailure{}}- Preflight failed (404 if template or access pass missing)
@spec list_card_template_pairs(keyword()) :: pairs_result()
Lists all pass template pairs for the account.
Template pairs combine an iOS and Android template for cross-platform pass issuance.
Parameters
opts- Options::client- Client struct (optional, defaults to config):page- Page number (default: 1):per_page- Results per page (default: 50, max: 100)
Returns
{:ok, [%CardTemplatePair.Summary{}], pagination}- List of pairs and pagination info{:error, reason, %HttpFailure{}}- Retrieval failed
@spec list_credential_profiles(keyword()) :: credential_profiles_result()
Lists all credential profiles for the account.
Rails returns a flat JSON array — no wrapper, no pagination — so the result
is {:ok, list} rather than {:ok, list, pagination}.
Parameters
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, [%CredentialProfile{}]}- List of credential profiles (may be empty){:error, reason, %HttpFailure{}}- Retrieval failed
@spec list_hid_orgs(keyword()) :: hid_orgs_result()
Lists HID Origo organizations registered to the account.
Rails returns a flat JSON array — no wrapper, no pagination.
Parameters
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, [%HidOrg{}]}- List of HID orgs (may be empty){:error, reason, %HttpFailure{}}- Retrieval failed
@spec list_landing_pages(keyword()) :: landing_pages_result()
Lists all landing pages for the account.
Rails returns a flat JSON array — there is no landing_pages wrapper and no
pagination, so the result is {:ok, list} rather than {:ok, list, pagination}.
Parameters
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, [%LandingPage{}]}- List of landing pages (may be empty){:error, reason, %HttpFailure{}}- Retrieval failed
@spec list_ledger_items(keyword()) :: ledger_items_result()
Lists ledger items for the account, paginated and optionally date-filtered.
Parameters
opts- Options::client- Client struct (optional, defaults to config):page- Page number (default: 1):per_page- Results per page (default: 50, max: 100):start_date- ISO8601 timestamp; filters items created on/after:end_date- ISO8601 timestamp; filters items created on/before
Returns
{:ok, [%LedgerItem{}], pagination}- List + pagination map{:error, reason, %HttpFailure{}}- 422 on bad date format
@spec list_webhooks(keyword()) :: webhooks_result()
Lists webhook subscriptions for the account.
Parameters
opts- Options::client- Client struct (optional, defaults to config):page- Page number (default: 1):per_page- Results per page (default: 50, max: 100)
Returns
{:ok, [%Webhook{}], pagination}- List + pagination map{:error, reason, %HttpFailure{}}- Retrieval failed
@spec publish_template( String.t(), keyword() ) :: publish_result()
Publishes a card template, moving it out of draft toward ready or in-review.
For Android+SEOS templates, Rails also syncs the template to the HID portal as
part of publish. If that sync fails, the template is rolled back to draft
and this call returns {:error, :validation_failed, failure} with a
field-tagged error message in failure.body_decoded["message"].
Parameters
template_id- The card template id to publishopts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CardTemplate.PublishResult{}}- 200 OK with{id, status}.statusis"publishing"(already in flight),"in-review"(Apple queued), or"ready"(Android, immediate).{:error, reason, %HttpFailure{}}- 404 if template missing, 422 on validation failure or HID-sync failure (for Android+SEOS).
@spec read_template( String.t(), keyword() ) :: template_result()
Retrieves a card template or card template pair by id.
The /v1/console/card-templates/:id endpoint serves both shapes: a single
template, or a pair containing two member templates. Match on the returned
struct to tell them apart.
Parameters
template_id- The template (or pair) id to retrieveopts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CardTemplate{}}- Single template{:ok, %CardTemplatePair{}}- Pair, with member templates under:templates{:error, reason, %HttpFailure{}}- Retrieval failed
@spec reveal_smart_tap(String.t(), map(), keyword()) :: smart_tap_reveal_result()
Reveals Smart Tap credentials for a card template, encrypted with the caller's ephemeral public key.
The caller decrypts the returned encrypted_private_key with their
corresponding private key. Each request must use a fresh ephemeral keypair —
Rails enforces single-use via the pubkey fingerprint (returns 409 if reused).
Parameters
template_id- The card template id (must be SmartTap protocol with asmart_tap_key)params- Map with::client_public_key- PEM-encoded public key string (required)
opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %SmartTapReveal{}}- Encrypted credentials envelope{:error, :not_found, %HttpFailure{}}- Template missing, not SmartTap, or nosmart_tap_key{:error, :conflict, %HttpFailure{}}- Thisclient_public_keyhas been used before{:error, :validation_failed, %HttpFailure{}}- Invalid PEM or save failure
@spec update_landing_page(String.t(), map(), keyword()) :: landing_page_result()
Updates an existing landing page.
The :kind field is immutable after creation. Sending a different value
returns 422.
Parameters
landing_page_id- The landing page ID to updateparams- Same fields ascreate_landing_page/2except:kindopts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %LandingPage{}}- Updated{:error, reason, %HttpFailure{}}- 404 if id missing, 422 on validation
Updates an existing card template.
Parameters
template_id- The template ID to updateparams- Fields to update (same options as create_template)opts- Options::client- Client struct (optional, defaults to config)
Returns
{:ok, %CardTemplate.Result{}}- Template updated successfully{:error, reason, %HttpFailure{}}- Update failed