Skip to Content
IntegrationsAPNGetting started

APN Sync — Onboarding

The APN connector setup creates a cross-account IAM role in your AWS Partner-linked account. FlowState assumes this role (with ExternalId protection) to call the Partner Central API on your behalf. No long-lived AWS credentials are stored in FlowState.

The wizard offers three equivalent paths. All three produce the same role with the same trust policy and the same AWS-managed policy attached. Choose the path that matches your team’s tooling.


Pre-step (common to all paths)

Before you choose a tab, FlowState:

  1. Creates an APN integration record for your tenant, initially disabled.
  2. Generates a fresh ExternalId, unique to your tenant, and stores it securely, encrypted at rest.
  3. Displays the following values — copy them, you will need them in all three paths:
ValueDescription
ExternalIdA unique secret that prevents the confused-deputy attack. Every IAM call FlowState makes must include this value.
FlowState principal ARNsThe list of IAM role ARNs that FlowState assumes the connector role from — one per FlowState service that touches Partner Central. Example: arn:aws:iam::<FLOWSTATE_AWS_ACCOUNT>:role/flowstate-<stage>-apn-outbound-writer. Paste the whole list; see Migration below.
Regionus-east-1 — Partner Central’s API endpoint is us-east-1 only. The role must be created in this region’s context (IAM is global, but the trust policy targets the us-east-1 endpoint).
Required policyarn:aws:iam::aws:policy/AWSPartnerCentralOpportunityManagement

The wizard auto-fills these values into the code blocks in each tab.


Tab 1 — OpenTofu

Best for: teams that manage infrastructure as code and want to version-control the connector role alongside their other AWS resources.

Copy the following block into a fresh directory in your Partner-linked AWS account and run the commands shown.

# main.tf — paste into a fresh directory in your AWS Partner-linked account terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.50" } } } provider "aws" { region = "us-east-1" # Partner Central API region — required } variable "external_id" { description = "ExternalId issued by FlowState — paste from the wizard" type = string sensitive = true } variable "flowstate_principal_arn" { description = "FlowState's role ARN — paste from the wizard" type = string } resource "aws_iam_role" "flowstate_apn_connector" { name = "FlowStateAPNConnector" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { AWS = var.flowstate_principal_arn } Action = "sts:AssumeRole" Condition = { StringEquals = { "sts:ExternalId" = var.external_id } } }] }) } resource "aws_iam_role_policy_attachment" "apn_managed" { role = aws_iam_role.flowstate_apn_connector.name policy_arn = "arn:aws:iam::aws:policy/AWSPartnerCentralOpportunityManagement" } output "role_arn" { description = "Paste this back into the FlowState wizard" value = aws_iam_role.flowstate_apn_connector.arn }

Run the following commands, substituting the values from the wizard:

tofu init tofu apply \ -var external_id=<ExternalId from wizard> \ -var flowstate_principal_arn=<FlowState principal ARN from wizard>

After tofu apply completes, copy the role_arn output value and paste it into the Role ARN field in the wizard.


Tab 2 — CloudFormation

Best for: teams that prefer one-click deployment or are not familiar with Terraform/OpenTofu.

Click the Launch in CloudFormation button in the wizard. This opens the AWS Console with the following pre-filled values:

  • Stack name: FlowStateAPNConnector
  • ExternalId: pre-filled from the wizard
  • FlowStatePrincipalArn: pre-filled from the wizard

The template that is deployed:

AWSTemplateFormatVersion: '2010-09-09' Description: FlowState APN connector role — grants FlowState least-privileged access to your Partner Central opportunities. Parameters: ExternalId: Type: String NoEcho: true Description: ExternalId issued by FlowState. Copy from the FlowState wizard. FlowStatePrincipalArn: Type: String Description: FlowState's role ARN. Copy from the FlowState wizard. Resources: FlowStateAPNConnectorRole: Type: AWS::IAM::Role Properties: RoleName: FlowStateAPNConnector AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Ref FlowStatePrincipalArn Action: sts:AssumeRole Condition: StringEquals: sts:ExternalId: !Ref ExternalId ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSPartnerCentralOpportunityManagement Outputs: RoleArn: Description: Paste this back into the FlowState wizard Value: !GetAtt FlowStateAPNConnectorRole.Arn

In the CloudFormation console:

  1. Confirm the pre-filled parameter values match what is shown in the FlowState wizard.
  2. Check I acknowledge that AWS CloudFormation might create IAM resources with custom names.
  3. Click Create stack.
  4. Wait for the stack status to reach CREATE_COMPLETE (approximately 30 seconds).
  5. Click the Outputs tab and copy the RoleArn value.
  6. Paste the ARN into the Role ARN field in the FlowState wizard.

Tab 3 — Manual (IAM Console)

Best for: teams that prefer step-by-step control via the AWS Console UI, or where IaC tooling is not available.

  1. Sign in to your AWS Partner-linked account at https://console.aws.amazon.com .
  2. Switch region to N. Virginia (us-east-1) using the region selector in the top-right corner.
  3. Open IAM → Roles → Create role.
  4. On the Trusted entity type screen, select AWS account.
  5. Select Another AWS account.
  6. In the Account ID field, paste the FlowState AWS account ID shown in the wizard.
  7. Check Require external ID and paste the ExternalId from the wizard into the field that appears.
  8. Click Next.
  9. In the permissions search, type AWSPartnerCentralOpportunityManagement and check the box next to the policy.
  10. Click Next.
  11. Set the role name to exactly FlowStateAPNConnector.
  12. Click Create role.
  13. Open the newly created role. In the Summary panel, copy the ARN (format: arn:aws:iam::<your-account-id>:role/FlowStateAPNConnector).
  14. Paste the ARN into the Role ARN field in the FlowState wizard.

If you prefer to use the IAM JSON editor for the trust policy, you can use the following policy document (with your values substituted):

{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"AWS": "<FlowState principal ARN from wizard>"}, "Action": "sts:AssumeRole", "Condition": {"StringEquals": {"sts:ExternalId": "<ExternalId from wizard>"}} }] }

Post-setup steps (common to all three paths)

After pasting the Role ARN from any tab:

Verify

Click Verify connection. FlowState calls sts:AssumeRole with your ExternalId and then calls partnercentral-selling:ListOpportunities(MaxResults=1). On success, the UI shows a green check and the AWS partner account ID that was discovered. If verification fails, the UI shows the raw AWS error message and suggests the three most likely fixes. See Troubleshooting.

Choose catalog

Select Sandbox (default, recommended) or Production.

  • Sandbox — test environment. Opportunities created here do not affect your real co-sell pipeline or partner tier. This is the recommended starting point.
  • Production — live Partner Central catalog. Switching from Sandbox to Production later requires a new integration setup. See Sandbox vs production.

Provision HubSpot properties

Click Provision properties. FlowState creates the flowstate_apn property group and all 10 custom properties in your HubSpot portal. A progress bar tracks each property. This step is idempotent.

Done

FlowState marks the APN integration enabled and turns on APN sync for your tenant, atomically. APN sync is now live. Deals with apn_sync_with_aws_enabled = true will begin syncing on the next HubSpot webhook event or polling cycle.


Migration — the principal ARN list grew

Applies to: every tenant whose connector stack was deployed before 2026-08-23.

What changed

The connector role’s trust policy lists the FlowState IAM roles that may assume it. That list gained a fifth entry, flowstate-<stage>-mcp-execution:

Principal rolePurpose
flowstate-<stage>-backendConnection verification, REST APN routes
flowstate-<stage>-apn-outbound-writerHubSpot → Partner Central sync
flowstate-<stage>-apn-inboundPartner Central events → HubSpot
flowstate-<stage>-hubspot-outDeal creation and materialisation
flowstate-<stage>-mcp-executionNew. The MCP server runs the APN connection tools in its own runtime, so it assumes the connector role directly rather than calling the backend.

Nothing was removed. The four earlier principals keep exactly the access they had.

Who must act

Any tenant who deployed the connector stack before the date above. Their trust policy still lists four principals, so the MCP tools enable_apn_integration and test_apn_connection fail with AccessDenied while the equivalent screens in the FlowState UI keep working. Tenants who onboard after that date get the full list from the wizard and need to do nothing.

How to tell whether a tenant still needs it

Any one of these is sufficient:

  • In FlowState, open Settings → Integrations → APN and click Verify connection. A failure that names the principal list as the likely cause is this migration.
  • In the AWS Partner-linked account: IAM → Roles → FlowStateAPNConnector<Catalog> → Trust relationships. Count the ARNs under Principal.AWS. Four means the stack predates the change; five means it is current.
  • Compare that trust policy against the ARN list currently shown in the onboarding wizard. The wizard always renders the current list.

What to re-run

Re-run the connector stack the same way it was created. No resource is replaced — only the trust policy is updated, and the role ARN, ExternalId and catalog are unchanged. No re-verification of the ExternalId is needed, and APN sync is not interrupted.

  • CloudFormation: update the existing stack with the current FlowstatePrincipalArns parameter value from the wizard (comma-separated). The wizard’s Launch in CloudFormation button pre-fills it.

  • OpenTofu — if you used the published module (source pointing at tofu/apn-connector.zip), from that directory:

    tofu init -upgrade tofu apply -var 'flowstate_principal_arns=[<the current list from the wizard>]'

    -upgrade is the part that matters — it re-downloads the module zip; a plain tofu init reuses the copy in .terraform/modules/ and the apply would report no changes. Note the variable is flowstate_principal_arns, a list.

  • OpenTofu — if you copied the inline files from the OpenTofu tab (no module source), -upgrade has nothing to re-download. Add the missing ARN to the Principal.AWS list in your own main.tf, then tofu apply.

  • Manual (IAM console): edit the trust policy JSON on FlowStateAPNConnector<Catalog> and add the missing ARN to Principal.AWS. Leave the existing ARNs and the sts:ExternalId condition in place.