> ## Documentation Index
> Fetch the complete documentation index at: https://imprint-b3c5d5af-partner-docs-latest.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Application event notifications

> Receive the authoritative result of an Imprint application server-side, and reconcile it with the client-side SDK result

## Overview

When a customer completes an Imprint application, you learn the outcome in **two
complementary ways**:

1. **The SDK result** — returned client-side, in the browser or mobile app, the
   moment the customer exits the Imprint application experience (see
   [Step 3 of Apply for a loan or credit card](https://docs.imprint.co/creating-an-application#step-3-handle-the-application-result)).
2. **The application event notification** — a signed, server-to-server webhook
   Imprint `POST`s to your configured endpoint when a credit decision is reached.

Both report on the same application, but they are designed for different jobs.
Use the **SDK result** to update the customer's experience immediately. Use the
**webhook** as the source of truth for your backend systems.

<Info>
  New to event notifications? Start with
  [Subscribe to event notifications](https://docs.imprint.co/guide-event-notifications)
  for setup, signature verification, and retry/idempotency handling.
</Info>

## SDK result vs. event notification

| | **SDK result** (client-side) | **Application event notification** (server-side) |
| - | - | - |
| **How you receive it** | Returned synchronously in the browser/app when the SDK exits | Asynchronous `POST` to your registered endpoint |
| **When it fires** | Every time the SDK exits — including abandonment and launch errors | At each server-side application milestone — intermediate events plus the terminal credit decision (see [When the webhook fires](#when-the-webhook-fires)) |
| **Possible values** | `OFFER_ACCEPTED`, `REJECTED`, `IN_PROGRESS`, `ERROR` | `EVALUATING`, `IDV_REQUIRED`, `PENDING_REVIEW`, `FROZEN`, `OFFERS_AVAILABLE`, `OFFER_ACCEPTED`, `REJECTED`, `ACCOUNT_FUNDED` (see [When the webhook fires](#when-the-webhook-fires)) |
| **Authority** | Client-reported; best-effort | Authoritative; the system of record |
| **Reliability** | Fires once; lost if the customer closes the tab first | Retried with exponential back-off until acknowledged |
| **Security** | In your client context | HMAC SHA-256 signed (`X-IMPRINT-HMAC-SIGNATURE`) |
| **Customer mapping** | Available in the client session | Carries `customer_id` and `partner_customer_id` |

### Why the status sets differ

The two channels answer **different questions**:

* The **SDK result** answers *"What happened in this browser/app session?"* — including
  the customer walking away or launching with a bad token.
* The **webhook** answers *"Where is this application in Imprint's pipeline?"* — it fires at
  each server-side milestone, both intermediate (e.g. `IDV_REQUIRED`, `OFFERS_AVAILABLE`) and
  terminal (`OFFER_ACCEPTED`, `REJECTED`).

A bad launch (`ERROR`) is a session outcome, not an application event — so it exists **only**
on the SDK side and **never** produces a webhook. `IN_PROGRESS` is also never a webhook
status, but it appears in two other places with **different meanings**, so do not treat them
as the same signal:

* The **SDK result** `IN_PROGRESS` means the customer *exited before finishing* (abandonment).
  Abandonment is not an application event and **never** produces a webhook.
* The **Application API** status `IN_PROGRESS` means the application is a *draft*: it has been
  created and not yet submitted. No webhook is sent for a draft. The first webhook for an
  application is `EVALUATING`, sent when decisioning starts after submit.

`OFFER_ACCEPTED` and `REJECTED` are terminal decisions that appear in both channels.

Use this mapping to decide what to expect from an **SDK result**:

| SDK result | What it means | Webhook sent? |
| - | - | - |
| `OFFER_ACCEPTED` | Approved and offer accepted — new member | **Yes** — `status: OFFER_ACCEPTED` |
| `REJECTED` | Rejected by Imprint | **Yes** — `status: REJECTED` <sup>(see note below)</sup> |
| `IN_PROGRESS` | Customer exited before finishing | **No** — abandonment is not an application event, and there is no `IN_PROGRESS` webhook <sup>(see [When the webhook fires](#when-the-webhook-fires))</sup> |
| `ERROR` | Invalid launch parameters (e.g. bad token) | **No** — not an application event |

<Warning>
  **`OFFER_ACCEPTED` and `REJECTED` are the same strings in both channels — but they
  are not interchangeable.** The SDK result is client-reported and best-effort; the
  webhook is authoritative. Two consequences:

  * **Don't treat the client-side `OFFER_ACCEPTED` as final** for fulfillment, accounting,
    or provisioning. Confirm it against the webhook (or the [API](https://docs.imprint.co/api-reference/payment-methods/retrieve-a-payment-method)).
  * **Don't wait for a webhook on an abandoned or errored session** — there will never be
    one. Handle `IN_PROGRESS` and `ERROR` entirely client-side.

  A customer can also close their browser *between* accepting the offer and the SDK
  returning, so you may receive the **webhook with no client-side result at all**. Always
  treat the webhook as the source of truth.
</Warning>

## When the webhook fires

Imprint sends an `APPLICATION` event notification when decisioning starts after
an application is submitted and when it reaches a terminal state, plus intermediate
notifications when the applicant must complete identity verification, when an
application is pended for manual review, when at least one offer becomes
available, and, for secured / funding products, when their deposit is funded:

| `status` | Meaning | Terminal? |
| - | - | - |
| `EVALUATING` | The application has been submitted and Imprint is decisioning it. This is the first notification for an application. | No |
| `IDV_REQUIRED` | The applicant must complete identity verification before underwriting can proceed. | No |
| `PENDING_REVIEW` | The application is pended for manual underwriting review before a decision can be made. | No |
| `FROZEN` | The applicant's credit file is frozen; they must lift the freeze with the credit bureaus before underwriting can proceed. | No |
| `OFFERS_AVAILABLE` | Decisioning is complete and at least one offer is available for the customer to accept. | No |
| `OFFER_ACCEPTED` | The application was approved and the customer accepted the credit offer — they are now a member. | Yes |
| `REJECTED` | The application was rejected by Imprint. | Yes |
| `ACCOUNT_FUNDED` | A secured / funding product's deposit has been funded. | No |

`EVALUATING` is an application-level notification — it fires once when
decisioning starts after submit, and its payload is not scoped to a specific
product. There is no notification before it: a draft application (Application
API status `IN_PROGRESS`) and an abandoned SDK session (SDK result
`IN_PROGRESS`) never produce a webhook.
`IDV_REQUIRED` is an application-level notification — its payload is not scoped
to a specific product. It is recoverable: once the applicant finishes identity
verification the application returns to underwriting, so expect a later
notification (`OFFERS_AVAILABLE`, `OFFER_ACCEPTED`, or `REJECTED`).
`PENDING_REVIEW` is an application-level notification — its payload is not scoped
to a specific product. It is recoverable: once manual underwriting review clears,
the application returns to underwriting, so expect a later notification
(`OFFERS_AVAILABLE`, `OFFER_ACCEPTED`, or `REJECTED`).
`FROZEN` is an application-level notification — its payload is not scoped to a
specific product. It is recoverable: once the applicant lifts the credit-bureau
freeze the application can re-enter underwriting, so expect a later notification
(`OFFERS_AVAILABLE`, `OFFER_ACCEPTED`, or `REJECTED`).
`OFFERS_AVAILABLE` is an application-level notification — it fires once every
product on the application has been decisioned and at least one offer is
available, not when the first offer is produced, and its payload is not scoped
to a specific product.
`ACCOUNT_FUNDED` is only emitted for secured / funding products.

After the `EVALUATING` notification, the interval before the next one is usually
seconds, but it can occasionally be longer while Imprint completes decisioning. No
notification is sent in the meantime and no action is required on your side: keep the
application open and wait for the next notification. If you poll Get Application in the
applicant's session, stop after 30 seconds and show an under-review state; the webhook
delivers the result. Do not submit the application again or create a new one for the
same applicant. This applies
only to a submitted application that is being decisioned; a draft that has not been
submitted produces no notification at all, however long the applicant takes.

<Note>
  A `REJECTED` notification is only delivered when Imprint can give you enough
  context to act on it — i.e. the application carries a `partner_customer_id`
  and/or maps to a known customer. If neither is available, the rejection is not
  sent, because it would not be actionable on your side.
</Note>

## Payload

See also the
[Application Event reference](/event-notifications#application-event).

| Property | Required | Type | Description |
| - | - | - | - |
| `application_id` | TRUE | String | Imprint's unique identifier for the application. Pass it to `GET /v2/applications/{application_id}` for the full state. |
| `status` | TRUE | String | `EVALUATING`, `IDV_REQUIRED`, `PENDING_REVIEW`, `FROZEN`, `OFFERS_AVAILABLE`, `OFFER_ACCEPTED`, `REJECTED`, or `ACCOUNT_FUNDED` (secured / funding products) |
| `product_types` | TRUE | Array of String | The product types on the application. A single-product application has one entry; a multi-product application (for example a credit card with a secured-card backup) lists each. For `OFFERS_AVAILABLE` this is limited to the products that actually have an offer ready, so a rejected or skipped backup is excluded. For `OFFER_ACCEPTED`, `COMPLETED`, and `ACCOUNT_FUNDED` it contains only the product the event concerns. |
| `created_at` | TRUE | Timestamp | RFC-3339 time the application was created. |
| `updated_at` | TRUE | Timestamp | RFC-3339 time of this decision. |
| `expires_at` | FALSE | Timestamp | The RFC-3339 timestamp after which the application expires if it has not been completed. Omitted when not yet known, such as on the initial `IN_PROGRESS` / `EVALUATING` event. |
| `upgraded` | TRUE | Boolean | Whether this application represents an upgrade/graduation of an existing account. Currently always `false`; it will be set to `true` on account graduation/upgrade once that is implemented. |
| `customer_id` | FALSE | String | Imprint's unique identifier for the customer. Present once a customer profile exists; on a `REJECTED` event it may be absent if no profile was created. |
| `partner_customer_id` | FALSE | String | Your identifier for the customer, as supplied when the session was created. Present only if you provided one. |

```json theme={null}
{
  "object": "APPLICATION",
  "data": {
    "application_id": "APLN-v1-7F3C1E20-4B8A-4E11-9C6D-2A5F0B7D3E91",
    "status": "OFFER_ACCEPTED",
    "product_types": ["SECUREDCREDITCARD"],
    "created_at": "2025-02-13T19:08:07.000Z",
    "updated_at": "2025-02-13T19:08:07.000Z",
    "expires_at": "2025-03-10T19:08:07.000Z",
    "upgraded": false,
    "customer_id": "2EE24580-B97B-4949-A65C-929CCB9B9B8D",
    "partner_customer_id": "PARTNER_USER_456"
  }
}
```

## Recommended handling

<Steps>
  <Step title="Update the UI from the SDK result">
    On SDK exit, react to the client-side result immediately — for
    `OFFER_ACCEPTED`, show a success banner or route the customer to a page to
    learn more about the credit card rewards. Treat this as provisional.
  </Step>

  <Step title="Confirm and persist from the webhook">
    When the `APPLICATION` webhook arrives, verify the signature, then record the
    decision against the `customer_id` / `partner_customer_id` as the source of
    truth for fulfillment, accounting, and downstream systems. When present,
    store `expires_at` so you can re-engage customers who have not finished
    before the application expires.
  </Step>

  <Step title="Deduplicate">
    Use `application_id`, `status`, and `updated_at` to ignore duplicate
    deliveries (Imprint retries until you acknowledge with a `2XX`).
  </Step>

  <Step title="Don't block on a webhook for non-decisions">
    `IN_PROGRESS` and `ERROR` SDK results never produce a webhook. Handle them
    entirely client-side.
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.