Guardrails

Override prompt injection and DLP policy for one customer

A Customer can override your organization’s prompt injection protection and data loss prevention policy. Use it when one of your end customers needs a different posture from the rest: enforcement for a tenant that handles regulated data while the others stay in alert mode, or a relaxed threshold for a tenant whose traffic keeps tripping false positives.

Overrides are sparse. A customer sets only the fields it cares about and inherits everything else, so raising an organization threshold moves every customer that did not pin that field. Omitting a field and sending it as null both mean inheritance.

Authentication

These endpoints use your production key (mg_), the same as the rest of the Customers API. Customer guardrails must be enabled for your organization; without it these endpoints return 403. Contact support to enable it.

How an override reaches a request

Whether a customer may relax the organization policy depends on how the request names the customer, not on how the override was written:

How the request names the customerWhat the override can do
The request is made with a customer API keyTighten or relax, exactly as written
The request names the customer itself, with the customer fieldTighten only, anything that loosens the organization policy is ignored

The second row is a security boundary, not a limitation to work around. Any organization-level key can name any customer, so a caller could otherwise point at whichever customer has the weakest policy and escape your protections. If you need a customer to run a genuinely looser policy, give it a customer API key.

A relaxation written for a customer that is only ever named with the customer field is silently inert. GET reports the policy as if the customer were key-pinned, so it will show the relaxed value while requests keep running the organization policy.

pi_allowlist_patterns is unioned with the organization’s list rather than replacing it, so a customer adds its own exceptions but never drops the ones your organization curated. Adding an exception always loosens, so it applies only to customer-API-key traffic.

Customers and projects do not mix

Customers and projects are unrelated concepts. Projects group your organization’s own workloads; Customers are the end tenants you resell Gateway to. A request that carries both a customer and any project scope (a project-scoped API key, the X-Project-Id header, or the project_id field) is rejected with 400 and the code customer_project_conflict. Send one or the other.

Prompt injection

PUT /v1/customers/{customer_id}/pi-settings replaces the override as a whole.

FieldDescriptionType
pi_modeDirect-injection mode: off, alert, or blockenum
pi_block_thresholdDirect-injection block threshold, 0 to 1. Must be at least the organization’s pi_pass_threshold.number
pi_indirect_modeIndirect-injection mode, a separate axis from pi_mode: off, alert, or blockenum
pi_tier2a_block_thresholdIndirect-injection heuristic-confidence threshold, 0 to 1number
pi_tier2b_block_thresholdIndirect-injection embedding-similarity threshold, 0 to 1number
pi_output_actionWhat to do when the response-side check fires: observe, redact, route, block, or escalateenum
pi_fail_closedWhether to reject requests when detection is unavailable. Defaults to failing open.boolean
pi_allowlist_patternsRegexes whose matching segments skip scanning, max 20. Unioned with the organization’s listlist of strings

pi_pass_threshold, pi_input_action, pi_safer_vendor_route, and pi_log_full_text_on_block stay at the organization level and are rejected with a 422 here, for the same reasons they are not project-overridable.

cURL
curl -X PUT https://api-gateway.merge.dev/v1/customers/{customer_id}/pi-settings \
-H "Authorization: Bearer mg_<your_production_key>" \
-H "Content-Type: application/json" \
-d '{
"pi_mode": "block",
"pi_block_threshold": 0.7
}'

The response carries both layers, so you never merge them yourself:

{
"override": { "pi_mode": "block", "pi_block_threshold": 0.7, "pi_indirect_mode": null },
"effective": { "pi_mode": "block", "pi_block_threshold": 0.7, "pi_indirect_mode": "alert" },
"inherited_fields": ["pi_indirect_mode", "pi_output_action", "pi_fail_closed"]
}

An override can also disable protection for one customer: with the organization in block mode, {"pi_mode": "off"} turns the direct axis off for that customer’s traffic, but only for requests made with that customer’s own API key (see How an override reaches a request). A customer override cannot enable protection the organization has not configured at all; it adjusts the organization policy, it does not create one.

Data loss prevention

PUT /v1/customers/{customer_id}/dlp-settings replaces the override as a whole. The payload is keyed by entity type under override:

cURL
curl -X PUT https://api-gateway.merge.dev/v1/customers/{customer_id}/dlp-settings \
-H "Authorization: Bearer mg_<your_production_key>" \
-H "Content-Type: application/json" \
-d '{
"override": {
"US_SSN": { "action": "block" },
"EMAIL_ADDRESS": { "enabled": false }
}
}'
FieldDescriptionType
enabledWhether this entity is scanned for this customerboolean
actionWhat to do on a match: log, redact, or blockenum

Both fields are optional, so {"action": "block"} changes the action and inherits whether the entity is scanned. The entity must already exist for your organization, either as a seeded rule or a custom one, otherwise the write is rejected with a 422 naming the unknown types.

The response returns your override plus every entity in the organization’s catalog with the merge applied, in the same shape as the project DLP response.

Inheriting again

DELETE on either resource clears the override so the customer inherits the organization policy as a whole. PUT with an empty body ({} for PI, {"override": {}} for DLP) does the same thing. To drop one field while keeping the rest, send that field as null.

cURL
curl -X DELETE https://api-gateway.merge.dev/v1/customers/{customer_id}/pi-settings \
-H "Authorization: Bearer mg_<your_production_key>"

Propagation and status codes

Guardrail changes reach request enforcement within about 60 seconds. The write is confirmed only after the configuration is durably stored; a storage failure returns 502 and leaves the previous policy in force.

CodeWhen
400The request combines customer with a project scope (customer_project_conflict)
403Customer guardrails not enabled for your organization, or the customer is inactive
404Unknown customer, or a customer belonging to another organization
422Validation: an org-only field, an unknown DLP entity type, more than 20 allowlist patterns, or a pi_block_threshold below the organization’s pi_pass_threshold

You can also view and edit a customer’s guardrails in the dashboard, on the customer’s Configuration tab.

Next steps