API REFERENCE

Beta

Reconfirm a Workflow

Runs a workflow again under its existing handle, either against the data currently staged in its session or against a revised set, which is recorded as the session’s new snapshot.

The workflowId does not change. A new runId is issued, and Read a Workflow afterwards serves the reconfirm’s progress and then its results. From the outside you are reconfirming the same workflow, at the same URL, with the same handle.

Get the URL to submit against from your Pitchpoint Account Representative.

A reconfirm is billed as its own workflow, not a free retry. It is not a way to re-fetch results you already have — for that, read the workflow, which costs nothing.

Sample

url="https://api.pointservices.com/riskinsight-services-ws/resources/v1/workflows/wfpop_0000000000002080001"
curl -X POST "${url}" \
  -H "Authorization: Bearer your_access_token_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "correlationId": "alpha_numeric_string_to_help_identify_this_reconfirm"
  }'

Header Properties

Property Value Required?
Authorization Bearer your token true
Content-Type application/json true
Accept application/json false
X-PPS-UserAlias your value false
X-PPS-UserAgent your value false
X-PPS-CorrelationID your value false
Idempotency-Key a V4 UUID false

Send Content-Type: application/json on every POST, including one with no body at all. In deployed environments a request that arrives without it is refused by edge protection in front of the application, with a 403 carrying an HTML body rather than any response documented here — and because the service never sees the request, nothing can explain it to you. A local or unprotected deployment may accept the same request, so do not take a working call there as evidence the header is optional.

Accept is not enforced — a request without it is answered normally with JSON — but send it anyway, so that a future change to content negotiation cannot alter what you receive.

X-PPS-CorrelationID is a support-tracing header and is not the same thing as the correlationId field in a request body. Only the body field is recorded against an order and searched by Find Workflows; setting the header globally in your HTTP client does not make your orders findable.

Idempotency-Key makes a retry of this call safe: send the same request again with the same key and you get the first response back, marked X-Pps-Idempotent-Replay: true, instead of the work being done twice. Use a new V4 UUID for each request. A key can be 1 to 255 characters; never put sensitive data in it. See Retrying Safely.

See the Common Headers guide for details on the optional X-PPS-* headers above.

Path Parameters

Property Description Type
workflowId (mandatory) The wfpop_ handle of the workflow to reconfirm. Accepted with or without the prefix. A wfrunpop_ runId addresses nothing and will not work here. string

Check reconfirmAvailable first

Read the workflow and check workflow.reconfirmAvailable before posting here.

The gate is the reconfirmAvailable flag. Compare it against true explicitly: it is optional on the wire, and an absent field means “not available”, not an error.

reconfirmAvailable: false does not necessarily mean the product can never be reconfirmed. A product offering several follow-ups has no single default, so the operation declines to choose rather than guessing. Read the flag as “a reconfirm is available here with no further input from you.”

Request Data Properties

The body is optional, and which one you send decides what the workflow runs against.

You send The workflow runs against
no body, an empty body, whitespace only, or {} the session’s current data (anything re-staged since the original order is included)
{"correlationId": "..."} the session’s current data (anything re-staged since the original order is included), with this run tagged by your value
{"terms": [ ... ]} revised data, recorded as the session’s new snapshot — a complete restatement, not a patch
{"product": { ... }} the session’s current data (anything re-staged since the original order is included). product is ignored; the workflow keeps its own.
null, a JSON array, a bare string, or malformed JSON nothing. Rejected with 400.
Property Description Type
terms (optional) A complete restatement of the data, recorded as the session’s new snapshot. Anything you leave out is absent from the new snapshot, not inherited. Omit the key entirely to record nothing and run against the session’s current data — do not send [], which is rejected. array
referenceNumber (optional, and only with terms) The loan’s reference number, recorded on the new snapshot exactly as on Stage Data. Like the terms it restates the loan: a reconfirm with terms but without referenceNumber clears the loan’s reference number. Sent without terms it is a 400 VALIDATION_ERROR, since no snapshot is recorded. Leading and trailing whitespace is trimmed, and a blank value is treated as absent; longer than 255 characters is a 400. A value that resembles SQL or markup is refused at the edge with no JSON body, so encode such a value (Base64, for instance) rather than sending it raw. string
correlationId (optional) Your own reference for this run, at most 255 characters. Never inherited from the original run. Leading and trailing whitespace is trimmed, and a blank value is treated as absent. Longer than 255 characters is a 400 VALIDATION_ERROR, and no run is started. A value that resembles SQL or markup is refused at the edge with no JSON body, so encode such a value (Base64, for instance) rather than sending it raw. Not the same as a term’s correlationId; see Correlation ids on terms. string

Do not name a product. It is inherited from the workflow you are reconfirming. A product in the body, like any other field besides terms and correlationId, is ignored rather than rejected, so it can’t change what runs. The service runs that product’s one default follow-up — for ADV, a RefreshOrder, even when the original run was a FirstOrder. Expect productName to change on the next read; that is the follow-up, not a mistake.

Send Content-Type: application/json even when you send no body. In deployed environments a request that omits it is refused by edge protection with a 403 carrying an HTML body, before this service sees it.

Webhook deliveries from a reconfirm

A reconfirm fires its own events, exactly as the first run did. The delivery carries the same workflowId and the new runId, so a handler keyed on workflowId needs no special case for reconfirms.

correlationId belongs to the run, not the workflow, and is not inherited. Send a new one on the reconfirm body if you match deliveries on it; otherwise the delivery carries no correlationId at all.

Receiving Deliveries covers the envelope and the two ids it carries.

Responses

Not every response carries the same body. Branch on the Content-Type first, and then on what the body contains. application/json is the messages envelope described on this page: read messages[].code. application/problem+json is a problem document, with type, title, status, detail and instance and no messages key: read type, and compare it as the whole URI (for example https://pointservices.com/problems/concurrent-modification). Some rejections carry no JSON at all. A client that calls its JSON parser on every non-2xx body, or that reads messages[0].code without first checking that messages is present, will fail on the responses it is most likely to meet. See Error handling for the whole rule.

202

Accepted for processing. The same workflowId, a new runId, and status back to processing.

A retry under the same Idempotency-Key returns this same 202, byte for byte, with the header X-Pps-Idempotent-Replay: true, naming the same runId. No second run is started or billed. A key belongs to the workflowId in the URL, so retry with the identical URL. See Retrying Safely.

Property Description Type
workflow (present) The workflow, now running its reconfirm. Same shape as a start acknowledgment. object
messages (present) Always an array, never null. Carries one message whose code is ACCEPTED. array

As with any acknowledgment, no timestamps are set and reconfirmAvailable is false. Whether it returns to true after this run depends on the product, as described above.

Example:

{
  "workflow": {
    "workflowId": "wfpop_0000000000002080001",
    "runId": "wfrunpop_0000000000002080002",
    "sessionId": "0000000000013500001",
    "correlationId": "alpha_numeric_string_to_help_identify_this_reconfirm",
    "product": {
      "service": "ADV",
      "model": "RefreshOrder"
    },
    "productType": "ADV",
    "productName": "RefreshOrder",
    "status": "processing",
    "reconfirmAvailable": false
  },
  "messages": [
    {
      "code": "ACCEPTED",
      "text": "workflow accepted for reconfirmation",
      "timestamp": "2026-08-07T16:20:04Z"
    }
  ]
}

Note the runId differs from the original run’s while the workflowId is unchanged. That is the whole lineage model: one handle, many runs.

400

The reconfirm was refused and nothing was billed. Causes: "terms": [], or terms containing an element that is not an object, carries other than exactly one key, or carries a key that is not one of the eleven branch keys; a value in a term that cannot be read as its field’s type; a correlationId or referenceNumber longer than 255 characters; a referenceNumber sent without terms. A body that is null, an array, a bare string or malformed JSON, and a Content-Type naming an unusable character set, are refused before evaluation, as problem documents. Also a workflow whose product no longer resolves to a reconfirmable product — a 400 you can meet without sending anything wrong. An Idempotency-Key that is blank, longer than 255 characters, or already used with a different body is also refused with VALIDATION_ERROR. A 400 is never stored. After fixing a problem in the body, send it again with the same key. After a key-reuse 400, see Retrying Safely.

A 400 arrives in two different body shapes, decided by how far the request got before it was refused. Branch on the Content-Type: application/json is the messages envelope, and application/problem+json is a problem document.

A value this service evaluated and rejected carries the messages envelope, with Content-Type: application/json and the code VALIDATION_ERROR.

Property Description Type
messages (present) Always an array, never null. Carries one message whose code is VALIDATION_ERROR. array
messages[].code (present) Always VALIDATION_ERROR on this shape. string
messages[].text (present) Human-readable description of what was wrong. Never machine-parsed — the wording is not contractual. string
messages[].timestamp (present) RFC 3339 UTC with a trailing Z. Fractional seconds appear only when they are not zero, so parse this value rather than slicing it. string

Example:

{
  "messages": [
    {
      "code": "VALIDATION_ERROR",
      "text": "A reconfirm request's correlationId must be at most 255 characters",
      "timestamp": "2026-08-07T15:01:42Z"
    }
  ]
}

A request refused before any value was evaluated carries a problem document instead, with Content-Type: application/problem+json and no messages key and no VALIDATION_ERROR code. Its type tells you which case it is:

Cause type
A body that could not be read as a reconfirm request at all: malformed JSON, a literal null body, a JSON array or bare value where an object was expected, or a field that can’t be read as its type about:blank
A Content-Type header naming a character set this service cannot use. It is refused before the body is read, so it says nothing about what you put in it. https://pointservices.com/problems/invalid-request

Example:

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "Malformed JSON",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

A client that reads messages[0].code on every 400 without checking that messages exists will throw on the problem-document shape. Branch on the Content-Type, or on the presence of messages, not on the status.

No run is started and the workflow is left exactly as it was.

401

No credential the platform could accept reached the service.

The body is a JSON problem document, not the messages envelope, and the response carries a WWW-Authenticate: Bearer realm="Helix" challenge. Read the machine-readable part from type; title and detail are human copy and are not contractual.

Property Description Type
type (present) An absolute URI identifying the problem. about:blank when no credential was sent at all. string
title (present) Short human-readable summary. string
status (present) Repeats the HTTP status code. number
detail (present) Human-readable explanation. Never machine-parsed. string
instance (present) An identifier for this one request. Quote it when contacting support. string

Examples:

{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required. Present a bearer access token in the Authorization header.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

{
  "type": "https://pointservices.com/problems/invalid-token",
  "title": "The access token was not accepted",
  "status": 401,
  "detail": "The access token was rejected.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

The second form carries WWW-Authenticate: Bearer realm="Helix", error="invalid_token", and is what a token the service will not accept returns.

The invalid-token type deliberately does not say why the token was refused: the platform cannot tell an expired token from a revoked, badly signed or malformed one. Treat every invalid-token the same way.

Refresh your token on a 401, and only on a 401. An expiring token moves a call from 200 to 401, never to 403. Obtain a fresh access token and retry the request once. If it fails again, stop and surface the error rather than looping — repeated attempts with a credential the service has already refused will meet the rate throttle described below.

403

Your credential was understood but you are not permitted to reconfirm this workflow. No run is started and nothing is billed.

A 403 is an authorization decision: your identity was established and the answer is still no. It is never a statement about your token, so refreshing the token will not turn it into a 200. A refused request leaves nothing behind, so there is nothing to clean up.

The body is a problem document (application/problem+json), not the messages envelope, so there is no code to branch on. Its type is one of two values:

type Meaning
about:blank The request was denied before the operation itself ran.
https://pointservices.com/problems/not-authorized A policy decision about the specific resource or product you named.

Example:

{
  "type": "https://pointservices.com/problems/not-authorized",
  "title": "Not authorized",
  "status": 403,
  "detail": "The authenticated identity is not permitted to perform this action.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

A 403 can also come from the edge, before this service is reached, when a request omits Content-Type or carries a value resembling SQL injection or cross-site scripting. That refusal carries an HTML body, not a problem document, and this service never sees it. Check the Content-Type of the response before you parse it. A value that legitimately contains such text should be encoded — Base64, for instance — rather than sent raw.

404

No workflow exists with this identifier, or the path you called is not served. Check you are using the wfpop_ workflowId and not a wfrunpop_ runId.

When this API answers, the body is a problem document (application/problem+json) in both cases, and its type tells them apart.

https://pointservices.com/problems/not-found means the identifier you sent did not resolve.

Property Description Type
type (present) https://pointservices.com/problems/not-found here. Compare it as the whole URI. string
title (present) Short human-readable summary. string
status (present) Repeats the HTTP status code. number
detail (present) Human-readable explanation naming what was not found. Never machine-parsed. string
instance (present) An identifier for this one request. Quote it when contacting support. string

Example:

{
  "type": "https://pointservices.com/problems/not-found",
  "title": "No such resource",
  "status": 404,
  "detail": "Workflow[wfpop_0000000000002080001] not found",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

Treat this as a single outcome: nothing in the body narrows down why the identifier did not resolve. Check the identifier you sent, and the tenancy of the credential you sent it with. An identifier this API has already issued to you is readable the moment you receive it, so a 404 on one is final rather than a race. Retrying will not make it appear.

about:blank means the path itself is not served here, so the request never reached this operation: a wrong host, or an environment where this API is not deployed.

A URL missing the /riskinsight-services-ws/resources/v1 path prefix does not reach this API at all. The 404 then comes from infrastructure in front of it, and carries no body this API defines, so don’t try to parse it. If a 404 has no problem document, check the path prefix before anything else.

409

IDEMPOTENCY_IN_PROGRESS — an earlier request under the same Idempotency-Key is still running. This is the one 409 to retry: wait the number of seconds in the Retry-After header, then send the same request with the same key. If it persists for more than a few minutes, stop and follow When the 409 doesn’t go away.

RECONFIRM_NOT_AVAILABLE — workflow.reconfirmAvailable is false. This is the one error response on this API that carries the full envelope, including the workflow block, so you can read the current state from the refusal itself. Do not retry on a timer: wait until a read shows reconfirmAvailable is true, then post once.

A concurrent write to this workflow, which lost the race. This arrives as a concurrent-modification problem document, described below. Treat a WORKFLOW_WRITE_CONFLICT code in the envelope the same way. Either way the service does not retry it, so you decide whether to resubmit.

Branch on the Content-Type first, and only then on messages[].code. A 409 here arrives in two body shapes, and the corrective action differs by cause. Never branch on the status alone, and never read messages[0].code without checking that messages is present.

application/json carries the messages envelope:

Property Description Type
messages (present) Always an array, never null. array
messages[].code (present) One of the codes described above for this status. string
messages[].text (present) Human copy. Never machine-parsed. string
messages[].timestamp (present) RFC 3339 UTC with a trailing Z, fractional seconds only when they are not zero. string

application/problem+json carries a problem document with type https://pointservices.com/problems/concurrent-modification and no messages key. Another request changed the same resource while yours was in flight, and nothing from yours was applied. It carries no Retry-After, deliberately: read the resource again, decide whether your change still applies to what you now see, and resubmit only if it does. Don’t resend the same request on a timer.

Example:

{
  "type": "https://pointservices.com/problems/concurrent-modification",
  "title": "Concurrent modification",
  "status": 409,
  "detail": "The resource was modified by another request while this one was being processed. This request was not applied; re-read the resource before resubmitting.",
  "instance": "urn:pps:request:0000000000000000000000000000000000000000000000000000"
}

In either shape the conflict is final for that attempt: the service does not retry it for you. The one exception is IDEMPOTENCY_IN_PROGRESS, which always arrives in the messages envelope and which you retry after the Retry-After delay.

429

Refused by a rate throttle at the edge, before this service is reached. The throttle counts requests per source address across every endpoint on both the session and workflow surfaces. Because the edge sends this response before the request reaches the service, it is not described in the OpenAPI specifications or the API Explorer.

The refusal carries no body, no messages array and no Retry-After header, and this service never sees it, so it will not appear in any support trace.

Back off and resume. When following a workflow to completion, an interval that stays clear of the throttle is two seconds for the first two checks, then five, then ten seconds thereafter, with an overall deadline after which you stop and investigate.

500

An unhandled failure inside the service. The body is a problem document (application/problem+json) with type about:blank, not the messages envelope, so branch on the status alone. When you report the error to PPS, quote the document’s instance: it carries the same id as the x-pps-request-id response header, and it is what lets PPS find this exact request.

Retrying this call is not safe. A 500 means the outcome is unknown, not that nothing happened: a failure raised after the work was committed leaves that work in place. A reconfirm may have been started and billed. Do not simply retry. A 500 on this call is stored: a retry under the same Idempotency-Key returns the same 500. Read the workflow: if runId has changed or status is processing, the reconfirm was accepted. If not, reconfirm again under a new key. Without an Idempotency-Key, retrying blind is how one workflow becomes two, and nothing on this surface removes a duplicate for you.


Copyright © Pitchpoint Solutions. All rights reserved.