> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upsert a partner

> Stored partner (credentials are never set this way)

### Path parameters

<ParamField path="id" type="string" required>
  Partner ID
</ParamField>

### Request body

`TradingPartner`

<ParamField body="ack_sla_hours" type="integer (int32)">
  Per-partner acknowledgment SLA in hours. Strict retailers chargeback on late 997s, so this overrides the global `EDI_ACK_SLA_HOURS` for monitoring and alerting. `None` falls back to the global SLA.
</ParamField>

<ParamField body="ack_type" type="string">
  Which functional acknowledgment this partner receives: `997` (default) or `999` (Implementation Acknowledgment with IK3/IK4 error detail).
</ParamField>

<ParamField body="api_key_hash" type="string">
  SHA-256 hex of this partner's API key, set via `POST /v1/partners/:id/api-key`. The plaintext key is never stored.
</ParamField>

<ParamField body="as1" type="object" />

<ParamField body="as2" type="object" />

<ParamField body="delimiters" type="Delimiters" />

<ParamField body="id" type="string" required>
  Stable internal identifier, used in URLs and event payloads.
</ParamField>

<ParamField body="label" type="object" />

<ParamField body="name" type="string" required />

<ParamField body="our_gs_id" type="string" />

<ParamField body="our_isa_id" type="string" required />

<ParamField body="our_isa_qualifier" type="string" required>
  Our ISA qualifier/ID for this relationship.
</ParamField>

<ParamField body="overlay" type="object" />

<ParamField body="packing_slip" type="object" />

<ParamField body="partner_gs_id" type="string">
  GS application codes; default to the ISA IDs when omitted.
</ParamField>

<ParamField body="partner_isa_id" type="string" required />

<ParamField body="partner_isa_qualifier" type="string" required>
  The partner's ISA qualifier/ID (they are the receiver on our outbound).
</ParamField>

<ParamField body="tenant_id" type="string">
  Owning tenant. Every partner belongs to exactly one tenant; an API key issued for the partner therefore implies its tenant. Defaults to `default` so single-tenant deployments and pre-tenancy records work unchanged.
</ParamField>

<ParamField body="usage" type="string">
  ISA15 usage indicator: `P` production, `T` test.
</ParamField>

<ParamField body="validation" type="PartnerValidation" />

<ParamField body="van" type="object" />

<ParamField body="version" type="string">
  GS08 version, e.g. `004010`.
</ParamField>

### Response

`TradingPartner`

<ResponseField name="ack_sla_hours" type="integer (int32)">
  Per-partner acknowledgment SLA in hours. Strict retailers chargeback on late 997s, so this overrides the global `EDI_ACK_SLA_HOURS` for monitoring and alerting. `None` falls back to the global SLA.
</ResponseField>

<ResponseField name="ack_type" type="string">
  Which functional acknowledgment this partner receives: `997` (default) or `999` (Implementation Acknowledgment with IK3/IK4 error detail).
</ResponseField>

<ResponseField name="api_key_hash" type="string">
  SHA-256 hex of this partner's API key, set via `POST /v1/partners/:id/api-key`. The plaintext key is never stored.
</ResponseField>

<ResponseField name="as1" type="object">
  <Expandable title="as1">
    <ResponseField name="partner_email" type="string" required>
      The partner mailbox that receives our EDI attachments.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="as2" type="object">
  <Expandable title="as2">
    <ResponseField name="compress_outbound" type="boolean">
      Compress outbound payloads (CMS CompressedData, RFC 5402). Applied innermost: compress → sign → encrypt.
    </ResponseField>

    <ResponseField name="encrypt_outbound" type="boolean">
      Encrypt outbound payloads (S/MIME). Requires a \[`Security`] signer.
    </ResponseField>

    <ResponseField name="mdn_mode" type="MdnMode" />

    <ResponseField name="mic_algorithm" type="MicAlgorithm" />

    <ResponseField name="our_as2_id" type="string" required>
      Our AS2 identifier (the value partners address messages to).
    </ResponseField>

    <ResponseField name="partner_as2_id" type="string" required>
      The partner's AS2 identifier.
    </ResponseField>

    <ResponseField name="partner_cert_pem" type="string">
      The partner's X.509 certificate (PEM) — used to verify their inbound signatures and (later) to encrypt outbound payloads for them.
    </ResponseField>

    <ResponseField name="partner_url" type="string" required>
      The partner's AS2 endpoint URL we POST outbound documents to.
    </ResponseField>

    <ResponseField name="request_signed_mdn" type="boolean">
      Request a *signed* MDN (transport-level non-repudiation of receipt). Requires a configured \[`Security`] signer to verify; until then we accept unsigned MDNs.
    </ResponseField>

    <ResponseField name="require_encrypted_inbound" type="boolean">
      Require inbound messages from this partner to be encrypted. When set, a cleartext inbound message is rejected with a failure MDN. Defaults to `false`.
    </ResponseField>

    <ResponseField name="require_signed_inbound" type="boolean">
      Require inbound messages from this partner to be signed. When set, an unsigned inbound message is rejected with a failure MDN instead of processed. Defaults to `false` (accept unsigned) to preserve existing behavior; enable it — together with `partner_cert_pem` — to mandate message authentication for a partner. Verification of the signature itself still depends on a configured certificate.
    </ResponseField>

    <ResponseField name="sign_outbound" type="boolean">
      Sign outbound payloads (S/MIME). Requires a \[`Security`] signer.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="delimiters" type="Delimiters">
  <Expandable title="Delimiters">
    <ResponseField name="component" type="string" required />

    <ResponseField name="element" type="string" required />

    <ResponseField name="repetition" type="string" />

    <ResponseField name="segment" type="string" required />
  </Expandable>
</ResponseField>

<ResponseField name="id" type="string" required>
  Stable internal identifier, used in URLs and event payloads.
</ResponseField>

<ResponseField name="label" type="object">
  <Expandable title="label">
    <ResponseField name="darkness" type="integer (int32)">
      Print darkness (ZPL `^MD`, 0–30); `None` leaves the printer default.
    </ResponseField>

    <ResponseField name="height_dots" type="integer (int32)">
      Label length in dots (ZPL `^LL`). 1218 = 6' at 203 dpi.
    </ResponseField>

    <ResponseField name="partner_mark" type="string">
      A partner-required mark printed at the label's top edge (e.g. a routing or department code the retailer mandates).
    </ResponseField>

    <ResponseField name="width_dots" type="integer (int32)">
      Print width in dots (ZPL `^PW`). 812 = 4' at 203 dpi.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="name" type="string" required />

<ResponseField name="our_gs_id" type="string" />

<ResponseField name="our_isa_id" type="string" required />

<ResponseField name="our_isa_qualifier" type="string" required>
  Our ISA qualifier/ID for this relationship.
</ResponseField>

<ResponseField name="overlay" type="object">
  <Expandable title="overlay">
    <ResponseField name="element_overrides" type="ElementOverride[]">
      Force an element's value on the first matching segment of an outbound transaction (optionally scoped to a set) — e.g. a fixed qualifier.

      <Expandable title="ElementOverride">
        <ResponseField name="element" type="integer" required>
          1-based element position (element 1 is the first after the segment tag).
        </ResponseField>

        <ResponseField name="segment" type="string" required />

        <ResponseField name="transaction_set" type="string" />

        <ResponseField name="value" type="string" required />
      </Expandable>
    </ResponseField>

    <ResponseField name="extra_segments" type="OverlaySegment[]">
      Extra segments appended to outbound transactions (optionally scoped to a transaction set) — e.g. a partner-required `REF`/`N9`/`DTM`.

      <Expandable title="OverlaySegment">
        <ResponseField name="elements" type="string[]" />

        <ResponseField name="tag" type="string" required />

        <ResponseField name="transaction_set" type="string">
          Restrict to one transaction set (e.g. `856`); `None` applies to all.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="packing_slip" type="object">
  <Expandable title="packing_slip">
    <ResponseField name="footer_note" type="string">
      Optional footer note (return policy, compliance marks, partner-required statements).
    </ResponseField>

    <ResponseField name="logo_text" type="string">
      Optional logo / brand line printed above the seller name.
    </ResponseField>

    <ResponseField name="seller_name" type="string" required>
      Seller / shipper name printed in the header (the 'from' identity).
    </ResponseField>

    <ResponseField name="show_sscc" type="boolean">
      When true, render each carton's SSCC alongside its contents — required by retailers that scan the slip against the carton label.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="partner_gs_id" type="string">
  GS application codes; default to the ISA IDs when omitted.
</ResponseField>

<ResponseField name="partner_isa_id" type="string" required />

<ResponseField name="partner_isa_qualifier" type="string" required>
  The partner's ISA qualifier/ID (they are the receiver on our outbound).
</ResponseField>

<ResponseField name="tenant_id" type="string">
  Owning tenant. Every partner belongs to exactly one tenant; an API key issued for the partner therefore implies its tenant. Defaults to `default` so single-tenant deployments and pre-tenancy records work unchanged.
</ResponseField>

<ResponseField name="usage" type="string">
  ISA15 usage indicator: `P` production, `T` test.
</ResponseField>

<ResponseField name="validation" type="PartnerValidation">
  <Expandable title="PartnerValidation">
    <ResponseField name="accepted_inbound" type="string[]">
      If non-empty, inbound transaction sets not in this list are rejected (e.g. `['850', '860']` for a partner that only sends orders).
    </ResponseField>

    <ResponseField name="conditional_rules" type="ConditionalRule[]">
      If-then rules, e.g. 'when BEG02 is SA, a DTM segment is required'.

      <Expandable title="ConditionalRule">
        <ResponseField name="equals" type="string[]">
          Trigger values. Empty means 'when the element is present (non-empty)'.
        </ResponseField>

        <ResponseField name="require_element" type="object" />

        <ResponseField name="require_segment" type="string">
          Then this segment must be present somewhere in the transaction.
        </ResponseField>

        <ResponseField name="when_element" type="integer" required />

        <ResponseField name="when_segment" type="string" required>
          Trigger: segment tag + 1-based element position.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="count_checks" type="object">
      Count-balancing rules per inbound transaction set — `CTT01` must equal the number of `PO1` segments and friends. Checked only when the counter segment is present (pair with `required_segments` to mandate it).
    </ResponseField>

    <ResponseField name="element_constraints" type="ElementConstraint[]">
      Element-level constraints applied to matching segments anywhere in an inbound document — e.g. pin PO1-03 (unit of measure) to an allowed set.

      <Expandable title="ElementConstraint">
        <ResponseField name="allowed" type="string[]">
          If non-empty, the element must be one of these values.
        </ResponseField>

        <ResponseField name="element" type="integer" required>
          1-based element position, e.g. `3` for the PO1 unit of measure.
        </ResponseField>

        <ResponseField name="format" type="object" />

        <ResponseField name="max_len" type="integer">
          Maximum length (in characters) when the element is present.
        </ResponseField>

        <ResponseField name="min_len" type="integer">
          Minimum length (in characters) when the element is present.
        </ResponseField>

        <ResponseField name="required" type="boolean">
          If true, the element must be present (non-empty).
        </ResponseField>

        <ResponseField name="segment" type="string" required>
          Segment tag, e.g. `PO1`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="required_qualified" type="object">
      Qualified-segment requirements per inbound transaction set — the guide staple `required_references` can't reach beyond REF: 'a DTM\*002 (delivery date) must be present', 'an N1 loop with N101=ST'. The `'*'` key applies to every set.
    </ResponseField>

    <ResponseField name="required_references" type="object">
      REF qualifiers that must be present per inbound transaction set, e.g. `&#123;'850': ['DP']&#125;` to require a department-number reference on every PO.
    </ResponseField>

    <ResponseField name="required_segments" type="object">
      Segment tags that must be present per inbound transaction set, e.g. `&#123;'850': ['DTM', 'REF']&#125;` to require a date and reference on every PO. The `'*'` key applies to every inbound set.
    </ResponseField>

    <ResponseField name="segment_cardinality" type="object">
      Occurrence bounds per inbound transaction set, e.g. `&#123;'850': [&#123;'segment': 'BEG', 'min': 1, 'max': 1&#125;]&#125;` for 'exactly one BEG' or a guide's 'max 200 PO1 lines'. The `'*'` key applies to every set; a set-specific rule for the same segment takes precedence.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="van" type="object">
  <Expandable title="van">
    <ResponseField name="mailbox" type="string" required>
      Mailbox slug under the provider.
    </ResponseField>

    <ResponseField name="provider" type="string">
      `stateset-network` for our native managed network, or an interconnect key such as `sps-commerce` when a bridge is configured.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="version" type="string">
  GS08 version, e.g. `004010`.
</ResponseField>

### Status codes

| Code  | Meaning                                             |
| ----- | --------------------------------------------------- |
| `200` | Stored partner (credentials are never set this way) |
| `403` | Admin credential required                           |

<RequestExample>
  ```bash cURL theme={null}
  curl --request PUT \
    --url 'https://edi.stateset.com/v1/partners/{id}' \
    --header 'Authorization: Bearer YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
    "ack_sla_hours": 1,
    "ack_type": "string",
    "api_key_hash": "YOUR_API_KEY",
    "as1": {
      "partner_email": "string"
    },
    "as2": {
      "compress_outbound": true,
      "encrypt_outbound": true,
      "mdn_mode": "none",
      "mic_algorithm": "sha256",
      "our_as2_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "partner_as2_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "partner_cert_pem": "string",
      "partner_url": "string",
      "request_signed_mdn": true,
      "require_encrypted_inbound": true,
      "require_signed_inbound": true,
      "sign_outbound": true
    },
    "delimiters": {
      "component": ">",
      "element": "*",
      "repetition": "string",
      "segment": "~"
    },
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "label": {
      "darkness": 1,
      "height_dots": 1,
      "partner_mark": "string",
      "width_dots": 1
    },
    "name": "Two-Person Tent",
    "our_gs_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "our_isa_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "our_isa_qualifier": "string",
    "overlay": {
      "element_overrides": [
        {
          "element": null,
          "segment": null,
          "transaction_set": null,
          "value": null
        }
      ],
      "extra_segments": [
        {
          "elements": null,
          "tag": null,
          "transaction_set": null
        }
      ]
    },
    "packing_slip": {
      "footer_note": "string",
      "logo_text": "https://cdn.example.com/products/tent-2p.jpg",
      "seller_name": "string",
      "show_sscc": true
    },
    "partner_gs_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "partner_isa_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "partner_isa_qualifier": "string",
    "tenant_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "usage": "string",
    "validation": {
      "accepted_inbound": [
        "string"
      ],
      "conditional_rules": [
        {
          "equals": null,
          "require_element": null,
          "require_segment": null,
          "when_element": null,
          "when_segment": null
        }
      ],
      "count_checks": {},
      "element_constraints": [
        {
          "allowed": null,
          "element": null,
          "format": null,
          "max_len": null,
          "min_len": null,
          "required": null,
          "segment": null
        }
      ],
      "required_qualified": {},
      "required_references": {},
      "required_segments": {},
      "segment_cardinality": {}
    },
    "van": {
      "mailbox": "string",
      "provider": "string"
    },
    "version": "2026-08-01"
  }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "ack_sla_hours": 1,
    "ack_type": "string",
    "api_key_hash": "YOUR_API_KEY",
    "as1": {
      "partner_email": "string"
    },
    "as2": {
      "compress_outbound": true,
      "encrypt_outbound": true,
      "mdn_mode": "none",
      "mic_algorithm": "sha256",
      "our_as2_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "partner_as2_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "partner_cert_pem": "string",
      "partner_url": "string",
      "request_signed_mdn": true,
      "require_encrypted_inbound": true,
      "require_signed_inbound": true,
      "sign_outbound": true
    },
    "delimiters": {
      "component": ">",
      "element": "*",
      "repetition": "string",
      "segment": "~"
    },
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "label": {
      "darkness": 1,
      "height_dots": 1,
      "partner_mark": "string",
      "width_dots": 1
    },
    "name": "Two-Person Tent",
    "our_gs_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "our_isa_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "our_isa_qualifier": "string",
    "overlay": {
      "element_overrides": [
        {
          "element": null,
          "segment": null,
          "transaction_set": null,
          "value": null
        }
      ],
      "extra_segments": [
        {
          "elements": null,
          "tag": null,
          "transaction_set": null
        }
      ]
    },
    "packing_slip": {
      "footer_note": "string",
      "logo_text": "https://cdn.example.com/products/tent-2p.jpg",
      "seller_name": "string",
      "show_sscc": true
    },
    "partner_gs_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "partner_isa_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "partner_isa_qualifier": "string",
    "tenant_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "usage": "string",
    "validation": {
      "accepted_inbound": [
        "string"
      ],
      "conditional_rules": [
        {
          "equals": null,
          "require_element": null,
          "require_segment": null,
          "when_element": null,
          "when_segment": null
        }
      ],
      "count_checks": {},
      "element_constraints": [
        {
          "allowed": null,
          "element": null,
          "format": null,
          "max_len": null,
          "min_len": null,
          "required": null,
          "segment": null
        }
      ],
      "required_qualified": {},
      "required_references": {},
      "required_segments": {},
      "segment_cardinality": {}
    },
    "van": {
      "mailbox": "string",
      "provider": "string"
    },
    "version": "2026-08-01"
  }
  ```
</ResponseExample>
