Skip to content

Workload identities

A workload identity defines which external OpenID Connect tokens a workload can use and which Flint scopes it can receive. The identity stores the trusted issuer, audience, subject, and claim conditions. Creating one returns its configuration, with no secret to store. Use workload identity token exchange to exchange a matching issuer token for a short-lived Flint access token.

Manage identities#

Listing and retrieving identities requires accounts.workload_identities.read. Creating, updating, and archiving requires accounts.workload_identities.write. These scopes are available in test and live mode. They are separate from accounts.api_keys.read and accounts.api_keys.write, and partner apps cannot request them.

An identity belongs to the authenticated environment. A test credential manages identities only in its own sandbox; a live credential manages live identities. Send no mode or sandbox_id in the request. An ID outside that environment returns 404 RESOURCE_NOT_FOUND with param: "workload_identity_id", the same as an unknown ID.

API keys and CLI OAuth callers can grant only scopes they already hold in that environment. Trying to grant more returns 403 INSUFFICIENT_SCOPE; details[0].missing_scopes names the extra scopes. Dashboard owners and admins can manage identities. Creating, reactivating, or widening a live identity through the Dashboard requires fresh identity verification. If verification is needed, the request returns 403 IDENTITY_VERIFICATION_REQUIRED.

cURL
curl -X POST https://api.withflintpay.com/v1/workload-identities \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "GitHub deployment",
    "issuer": "https://token.actions.githubusercontent.com",
    "subject": "repo:example/store:ref:refs/heads/main",
    "claim_conditions": [
      {"claim": "repository_owner_id", "value": "12345678", "match": "exact"},
      {"claim": "repository_id", "value": "87654321", "match": "exact"}
    ],
    "scopes": ["commerce.orders.read"]
  }'

Flint checks the issuer's discovery document when creating the identity. Each merchant can have at most 100 non-archived identities across all environments.

GET /v1/workload-identities returns a cursor-paginated list. Set page_size from 1 to 100, with 20 returned by default, and pass next_page_token as the next request's page_token. Use status to filter by active, inactive, or archived; the default excludes archived identities. The timestamp filters are created_after, created_before, updated_after, and updated_before, with inclusive lower bounds and exclusive upper bounds. Sort with sort_by=created_at, last_used_at, or name, and sort_direction=asc or desc. The default is created_at descending, with workload_identity_id descending to break ties.

The identity resource#

FieldBehavior
workload_identity_idThe identity's ID, beginning with wid_.
nameYour label, from 1 to 100 characters.
statusactive, inactive, or archived. New identities are active.
modetest or live, from the authenticated environment. Read-only.
sandbox_idThe test identity's sandbox. Omitted on live identities. Read-only.
platformA computed, extensible description of the issuer's platform. Treat unfamiliar values as valid. Read-only.
issuerThe exact trusted issuer URL. Immutable after creation.
audienceThe audience the external token must have. Defaults to Flint's issuer URL, https://api.withflintpay.com on the production API. Immutable after creation.
subjectThe required subject or subject pattern, from 1 to 1,024 characters.
subject_matchexact by default, or glob.
claim_conditionsUp to 10 distinct conditions. Every condition has claim, value, and match; match defaults to exact and also accepts glob. All conditions must match.
scopesAt least one scope the identity can grant. Replacing this array replaces the whole set.
created_byA reference with resource_type (user, api_key, or workload_identity) and resource_id, identifying who created the identity. Read-only.
last_used_atWhen the identity was last used. Omitted if it has never been used.
created_at, updated_atCreation and last-change times, as RFC 3339 timestamps.
archived_atThe archive time. Omitted before the identity is archived.
versionThe current version. Send it as expected_version to require the version you reviewed.

Issuer and claim matching#

The issuer must be an HTTPS URL with a DNS host, at most 255 characters long. Only port 443 is allowed; omit credentials, query parameters, and fragments. Flint compares the issuer exactly. The issuer must expose public OpenID Connect discovery and signing keys; private network addresses and redirects are rejected.

Claim names refer to literal top-level scalar claims. Conditions cannot use the registered JWT claims iss, sub, aud, exp, nbf, iat, or jti; configure the issuer, subject, and audience through their own fields.

In a glob match, * matches characters other than :. A pattern can contain at most three * characters and cannot start with one. If the subject or any claim condition uses a glob, include at least one exact claim condition.

Shared issuers also require an exact condition that pins the workload to your tenant:

IssuerRequired exact condition
GitHub Actionsrepository_owner_id
GitLab.comnamespace_id
Buildkiteorganization_id
Vercelowner_id
CircleCIoidc.circleci.com/org-id

For Google Cloud's https://accounts.google.com issuer, use an exact numeric subject and no glob conditions. Microsoft issuers must identify a specific tenant; common, organizations, and consumers issuers are rejected.

For GitHub Actions, also pin repository_id to keep a renamed or recreated repository from matching only by its name.

Update and archive#

PATCH /v1/workload-identities/{workload_identity_id} accepts name, status, subject, subject_match, claim_conditions, and scopes. Omitted fields keep their current values. Arrays replace their current contents; send "claim_conditions": [] to remove all conditions when the resulting matching policy allows it. Include the current expected_version whenever you send claim_conditions or scopes. It is optional for scalar-only changes. An update that changes nothing preserves version and updated_at.

Set status: "inactive" to deactivate an identity, or status: "active" to reactivate it. A stale expected_version returns 409 VERSION_CONFLICT; retrieve the current identity, review the changes, and send its version with your next update.

cURL
curl -X PATCH https://api.withflintpay.com/v1/workload-identities/wid_01KWJ93G11C7MF8REX91MDS0CD \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"expected_version": 1, "status": "inactive"}'

DELETE /v1/workload-identities/{workload_identity_id} archives the identity and returns the resource with status: "archived" and archived_at set. You can pass expected_version as a query parameter to require the version you reviewed. Archiving is permanent; create a new identity if you need to replace it. An archived identity no longer counts toward the merchant's limit. Archived identities remain readable by ID and appear in lists with status=archived.

Errors#

  • HTTP 400
    A field is invalid. An invalid issuer or discovery document has an INVALID_VALUE detail on issuer. Correct the named field before retrying.
  • HTTP 403
    The caller lacks a required management scope or tried to delegate scopes it does not hold. Check details[0].missing_scopes.
  • HTTP 403
    Complete fresh identity verification in the Dashboard, then retry the live identity change.
  • HTTP 404
    The ID does not identify a workload identity in the authenticated environment.
  • HTTP 409
    VERSION_CONFLICTRefresh, then retry
    Retrieve the identity and review its current version before retrying the update.
  • HTTP 409
    The merchant already has 100 non-archived identities. Archive an unused identity before creating another.
  • HTTP 502
    EXTERNAL_SERVICE_ERRORRetry the same request
    Issuer discovery timed out or its server returned a temporary error. error_source is integration. Retry after the issuer recovers.

The Workload identity object#

Every field on a workload identity, as returned by retrieve and carried by the endpoints below.

Attributes

archived_atstring

Time the identity was archived. Omitted before archival.

audiencestringRequired
claim_conditionsarray of objectRequired

Bounded value array of top-level scalar claim conditions. Replaced as a whole on PATCH; [] clears it when the remaining policy is valid.

created_atstringRequired

Time the identity was created.

created_byobjectRequired

The user or credential that created a workload identity, identified by resource type and ID.

issuerstringRequired
last_used_atstring

Most recent use. Omitted before the first use.

modeenumRequired
  • test
  • live
namestringRequired
platformenumRequired

Computed from the issuer. New platform values may be added.

  • generic
  • github_actions
  • gitlab_ci
  • google_cloud
  • aws
  • azure
  • kubernetes
  • circleci
  • buildkite
  • vercel
  • fly_io
sandbox_idstring

The sandbox containing this identity. Present only in test mode.

scopesarray of stringRequired

Complete scope set granted to this identity. Replaced as a whole on PATCH.

statusenumRequired
  • active
  • inactive
  • archived
subjectstringRequired
subject_matchenumRequired
  • exact
  • glob
updated_atstringRequired

Time the identity last changed.

versionintegerRequired

Positive concurrency version. Increases on policy and lifecycle changes.

workload_identity_idstringRequired
JSON
{
  "audience": "https://api.withflintpay.com",
  "claim_conditions": [
    {
      "claim": "repository_owner_id",
      "match": "exact",
      "value": "123456"
    }
  ],
  "created_at": "2026-10-24T12:00:00Z",
  "created_by": {
    "resource_id": "usr_01K8ABCDEF0123456789ABCDEF",
    "resource_type": "user"
  },
  "issuer": "https://token.actions.githubusercontent.com",
  "mode": "live",
  "name": "Production deploy",
  "platform": "github_actions",
  "scopes": [
    "commerce.orders.read"
  ],
  "status": "active",
  "subject": "repo:acme/shop:ref:refs/heads/main",
  "subject_match": "exact",
  "updated_at": "2026-10-24T12:00:00Z",
  "version": 1,
  "workload_identity_id": "wid_01K8ABCDEF0123456789ABCDEF"
}

List workload identities#

GET/v1/workload-identities

Requires scope accounts.workload_identities.read or accounts.workload_identities.write

Returns identities in the authenticated environment, ordered by created_at descending and workload_identity_id descending by default. Archived identities are excluded unless status includes archived.

Query parameters

statusarray of enum

Filter by status. Repeat the parameter or send comma-separated values to match any of several. Omitted, the list leaves out archived rows; name archived to include them. Accepts repeated keys, comma-separated values, or mixtures. Values are trimmed and deduplicated in first-seen order; empty or unknown entries are rejected. Values within this filter are ORed; separate filters are ANDed.

  • active
  • inactive
  • archived
page_sizeinteger

Page size, default 20, max 100.

page_tokenstring

Opaque token returned by the previous list response.

sort_byenum

Field to sort by. Defaults to created_at; ties are broken by workload_identity_id.

  • created_at
  • last_used_at
  • name
sort_directionenum

Sort direction. Defaults to desc.

  • asc
  • desc
created_afterstring

Inclusive lower bound on created_at.

created_beforestring

Exclusive upper bound on created_at.

updated_afterstring

Inclusive lower bound on updated_at.

updated_beforestring

Exclusive upper bound on updated_at.

Response · 200

dataarray of objectRequired
metaobject

Metadata returned with a response: the `api_version`, `trace_id`, whether an idempotent request was replayed, and any warnings.

next_page_tokenstring
request_idstring
curl https://api.withflintpay.com/v1/workload-identities \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": [
    {
      "audience": "https://api.withflintpay.com",
      "claim_conditions": [
        {
          "claim": "repository_owner_id",
          "match": "exact",
          "value": "123456"
        }
      ],
      "created_at": "2026-10-24T12:00:00Z",
      "created_by": {
        "resource_id": "usr_01K8ABCDEF0123456789ABCDEF",
        "resource_type": "user"
      },
      "issuer": "https://token.actions.githubusercontent.com",
      "mode": "live",
      "name": "Production deploy",
      "platform": "github_actions",
      "scopes": [
        "commerce.orders.read"
      ],
      "status": "active",
      "subject": "repo:acme/shop:ref:refs/heads/main",
      "subject_match": "exact",
      "updated_at": "2026-10-24T12:00:00Z",
      "version": 1,
      "workload_identity_id": "wid_01K8ABCDEF0123456789ABCDEF"
    }
  ],
  "next_page_token": "opaque-next-page-token"
}

Create a workload identity#

POST/v1/workload-identitiesIdempotent

Requires scope accounts.workload_identities.write

Creates an active identity in the authenticated environment and validates issuer discovery. Dashboard callers creating live identities need fresh identity verification. Machine callers may grant only scopes they hold in this environment.

Request body

audiencestring

Immutable token audience. Defaults to Flint's configured issuer URL when omitted.

claim_conditionsarray of object

Bounded value array, at most 10. Defaults to []. Any glob requires an exact claim condition; shared issuers require tenant pinning.

issuerstringRequired

Immutable public HTTPS issuer with a DNS host, optional port 443, and no userinfo, query, or fragment. Compared exactly.

namestringRequired
scopesarray of enumRequired

Complete scope set to grant. Machine callers may grant only scopes they hold in the same environment.

  • accounts.api_keys.read
  • accounts.api_keys.write
  • accounts.devices.read
  • accounts.devices.write
  • accounts.organizations.read
  • accounts.organizations.write
  • accounts.workload_identities.read
  • accounts.workload_identities.write
  • analytics.read
  • checkouts.checkout_sessions.read
  • checkouts.checkout_sessions.write
  • checkouts.payment_links.read
  • checkouts.payment_links.write
  • commerce.bundles.read
  • commerce.bundles.write
  • commerce.catalog.read
  • commerce.catalog.write
  • commerce.credit_notes.read
  • commerce.credit_notes.write
  • commerce.delivery.read
  • commerce.delivery.write
  • commerce.gift_cards.adjustments.write
  • commerce.gift_cards.read
  • commerce.gift_cards.redemptions.write
  • commerce.gift_cards.secrets.write
  • commerce.gift_cards.write
  • commerce.inventory.read
  • commerce.inventory.write
  • commerce.inventory_locations.write
  • commerce.inventory_policies.write
  • commerce.invoices.read
  • commerce.invoices.write
  • commerce.orders.read
  • commerce.orders.write
  • commerce.products.read
  • commerce.products.write
  • commerce.promotions.read
  • commerce.promotions.write
  • commerce.refunds.read
  • commerce.refunds.tax_overrides.write
  • commerce.refunds.write
  • commerce.return_policies.write
  • commerce.return_reasons.write
  • commerce.returns.operations.write
  • commerce.returns.read
  • commerce.returns.resolutions.write
  • commerce.returns.write
  • commerce.subscription_plans.read
  • commerce.subscription_plans.write
  • commerce.subscriptions.read
  • commerce.subscriptions.write
  • customers.read
  • customers.sessions.write
  • customers.write
  • developer.feedback_reports.read
  • developer.feedback_reports.write
  • developer.partner_apps.read
  • developer.partner_apps.write
  • developer.request_logs.read
  • developer.request_logs.self.read
  • developer.resource_timelines.read
  • developer.sandboxes.read
  • developer.sandboxes.write
  • merchant_billing.read
  • merchants.account_sessions.write
  • merchants.locations.read
  • merchants.locations.write
  • merchants.onboarding.read
  • merchants.onboarding.write
  • merchants.profile.read
  • merchants.profile.write
  • money_movement.balance_transactions.read
  • money_movement.balances.read
  • money_movement.payout_settings.read
  • money_movement.payout_settings.write
  • money_movement.payouts.read
  • money_movement.payouts.write
  • payments.disputes.read
  • payments.disputes.write
  • payments.payment_intents.read
  • payments.payment_intents.write
  • payments.payment_method_domains.read
  • payments.payment_method_domains.write
  • payments.payment_methods.read
  • payments.payment_methods.write
  • payments.payment_options.read
  • reports.read
  • reports.write
  • risk.controls.write
  • risk.read
  • risk.reviews.write
  • settings.read
  • settings.write
  • webhooks.read
  • webhooks.write
subjectstringRequired
subject_matchenum
  • exact
  • glob

Response · 201

dataobjectRequired

A policy that grants API access to a workload authenticated by an external identity provider.

metaobject

Metadata returned with a response: the `api_version`, `trace_id`, whether an idempotent request was replayed, and any warnings.

request_idstring
curl -X POST https://api.withflintpay.com/v1/workload-identities \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "claim_conditions": [
      {
        "claim": "repository_owner_id",
        "match": "exact",
        "value": "123456"
      }
    ],
    "issuer": "https://token.actions.githubusercontent.com",
    "name": "Production deploy",
    "scopes": [
      "commerce.orders.read"
    ],
    "subject": "repo:acme/shop:ref:refs/heads/main"
  }'

Get a workload identity#

GET/v1/workload-identities/{workload_identity_id}

Requires scope accounts.workload_identities.read or accounts.workload_identities.write

Returns an identity in the authenticated environment, including an archived identity.

Path parameters

workload_identity_idstringRequired

Flint workload identity ID.

Response · 200

Same response as Create a workload identity.

curl https://api.withflintpay.com/v1/workload-identities/wid_01K8ABCDEF0123456789ABCDEF \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "data": {
    "audience": "https://api.withflintpay.com",
    "claim_conditions": [
      {
        "claim": "repository_owner_id",
        "match": "exact",
        "value": "123456"
      }
    ],
    "created_at": "2026-10-24T12:00:00Z",
    "created_by": {
      "resource_id": "usr_01K8ABCDEF0123456789ABCDEF",
      "resource_type": "user"
    },
    "issuer": "https://token.actions.githubusercontent.com",
    "mode": "live",
    "name": "Production deploy",
    "platform": "github_actions",
    "scopes": [
      "commerce.orders.read"
    ],
    "status": "active",
    "subject": "repo:acme/shop:ref:refs/heads/main",
    "subject_match": "exact",
    "updated_at": "2026-10-24T12:00:00Z",
    "version": 1,
    "workload_identity_id": "wid_01K8ABCDEF0123456789ABCDEF"
  }
}

Update a workload identity#

PATCH/v1/workload-identities/{workload_identity_id}Idempotent

Requires scope accounts.workload_identities.write

Updates mutable policy fields. expected_version is optional for scalar updates and required when claim_conditions or scopes is supplied. Arrays replace their entire value. Issuer and audience are immutable. Dashboard callers reactivating or widening live identities need fresh identity verification.

Path parameters

workload_identity_idstringRequired

Flint workload identity ID.

Request body

claim_conditionsarray of object

Bounded value array, at most 10. Defaults to []. Any glob requires an exact claim condition; shared issuers require tenant pinning.

expected_versioninteger

Version most recently read. Required when claim_conditions or scopes is supplied; optional for scalar updates.

namestring
scopesarray of enum

Complete scope set to grant. Machine callers may grant only scopes they hold in the same environment.

  • accounts.api_keys.read
  • accounts.api_keys.write
  • accounts.devices.read
  • accounts.devices.write
  • accounts.organizations.read
  • accounts.organizations.write
  • accounts.workload_identities.read
  • accounts.workload_identities.write
  • analytics.read
  • checkouts.checkout_sessions.read
  • checkouts.checkout_sessions.write
  • checkouts.payment_links.read
  • checkouts.payment_links.write
  • commerce.bundles.read
  • commerce.bundles.write
  • commerce.catalog.read
  • commerce.catalog.write
  • commerce.credit_notes.read
  • commerce.credit_notes.write
  • commerce.delivery.read
  • commerce.delivery.write
  • commerce.gift_cards.adjustments.write
  • commerce.gift_cards.read
  • commerce.gift_cards.redemptions.write
  • commerce.gift_cards.secrets.write
  • commerce.gift_cards.write
  • commerce.inventory.read
  • commerce.inventory.write
  • commerce.inventory_locations.write
  • commerce.inventory_policies.write
  • commerce.invoices.read
  • commerce.invoices.write
  • commerce.orders.read
  • commerce.orders.write
  • commerce.products.read
  • commerce.products.write
  • commerce.promotions.read
  • commerce.promotions.write
  • commerce.refunds.read
  • commerce.refunds.tax_overrides.write
  • commerce.refunds.write
  • commerce.return_policies.write
  • commerce.return_reasons.write
  • commerce.returns.operations.write
  • commerce.returns.read
  • commerce.returns.resolutions.write
  • commerce.returns.write
  • commerce.subscription_plans.read
  • commerce.subscription_plans.write
  • commerce.subscriptions.read
  • commerce.subscriptions.write
  • customers.read
  • customers.sessions.write
  • customers.write
  • developer.feedback_reports.read
  • developer.feedback_reports.write
  • developer.partner_apps.read
  • developer.partner_apps.write
  • developer.request_logs.read
  • developer.request_logs.self.read
  • developer.resource_timelines.read
  • developer.sandboxes.read
  • developer.sandboxes.write
  • merchant_billing.read
  • merchants.account_sessions.write
  • merchants.locations.read
  • merchants.locations.write
  • merchants.onboarding.read
  • merchants.onboarding.write
  • merchants.profile.read
  • merchants.profile.write
  • money_movement.balance_transactions.read
  • money_movement.balances.read
  • money_movement.payout_settings.read
  • money_movement.payout_settings.write
  • money_movement.payouts.read
  • money_movement.payouts.write
  • payments.disputes.read
  • payments.disputes.write
  • payments.payment_intents.read
  • payments.payment_intents.write
  • payments.payment_method_domains.read
  • payments.payment_method_domains.write
  • payments.payment_methods.read
  • payments.payment_methods.write
  • payments.payment_options.read
  • reports.read
  • reports.write
  • risk.controls.write
  • risk.read
  • risk.reviews.write
  • settings.read
  • settings.write
  • webhooks.read
  • webhooks.write
statusenum
  • active
  • inactive
subjectstring
subject_matchenum
  • exact
  • glob

Response · 200

Same response as Create a workload identity.

curl -X PATCH https://api.withflintpay.com/v1/workload-identities/wid_01K8ABCDEF0123456789ABCDEF \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a-unique-key" \
  -d '{
    "expected_version": 1,
    "name": "Release deploy",
    "status": "inactive"
  }'

Archive a workload identity#

DELETE/v1/workload-identities/{workload_identity_id}Idempotent

Requires scope accounts.workload_identities.write

Soft-archives the identity and returns it with status archived. The identity remains readable by ID and cannot be reactivated. Repeating DELETE without a stale fence returns the archived identity without changing its version.

Path parameters

workload_identity_idstringRequired

Flint workload identity ID.

Query parameters

expected_versioninteger

Optional version most recently read.

Response · 200

Same response as Create a workload identity.

curl -X DELETE https://api.withflintpay.com/v1/workload-identities/wid_01K8ABCDEF0123456789ABCDEF \
  -H "Flint-Version: 2026-09-07" \
  -H "Authorization: Bearer YOUR_API_KEY"

Was this helpful?