Scope API key to read-only access

We are implementing a data warehouse sync using the FieldPulse API and need to adhere to our internal least-privilege security policy. I have confirmed that the current API key we are using has full read/write access to all endpoints.

I have reviewed the following documentation:

  • API authentication overview (Using the FieldPulse API)
  • User roles and permissions (Managing User Roles and Permissions)

However, I cannot locate specific instructions for scoping an API key to read-only operations (GET requests only) or restricting access to specific resource types (e.g., work orders and customers only, excluding inventory modifications).

Environment:

  • FieldPulse account: Enterprise tier
  • Current API key created: 2025-09-15
  • Integration framework: Python 3.11, using official FieldPulse Python SDK v2.3.1

Questions:

  1. Does FieldPulse support fine-grained API key permissions (read-only vs. read-write)?
  2. Is it possible to scope a key to specific endpoints or resource types?
  3. If not natively supported, what is the recommended pattern for achieving least-privilege access for automated read-only integrations?

I can reproduce the current full-access behavior consistently across all tested endpoints. Please advise on available configuration options.

Parents
  • Hey Rachel — great question, and honestly this is something we could document better. Short answer: we don't currently support fine-grained scopes on API keys. A key is either valid (full access based on the account's feature tier) or it's not.

    The auth model right now is basically:

    • Your API key inherits the permissions of the user account that created it
    • There's no "read-only" key type or endpoint-level restrictions

    That said, for your use case, here are the workarounds I see teams use:

    Option 1: Service Account with Restricted User Role

    Create a dedicated user account in FieldPulse with the Viewer role (or custom role with "View" permissions only), then generate the API key from that account. The key will still technically be able to call POST/PUT endpoints, but the underlying user permissions will block mutations. You'll get 403s on write attempts, which is ... not elegant, but functional.

    Option 2: Reverse Proxy with Request Filtering

    Some teams put a lightweight proxy (nginx, AWS API Gateway, etc.) in front of our API that rejects anything except GET requests. Yeah, this is infrastructure you have to maintain, but it gives you surgical control.

    What we're actually building

    Scoped API keys with explicit read/write and resource-level permissions are on the roadmap for Q1 2026. I can't share the full spec yet, but think along the lines of:

    {
      "name": "Data Warehouse Sync",
      "scopes": ["work_orders:read", "customers:read"],
      "allowed_ips": ["10.0.0.0/8"]
    }

    No promises on exact syntax, but that's the direction.

    For now, I'd recommend Option 1 — it's what most of our Enterprise customers do for read-only ETL jobs. Want me to walk through setting up a restricted service account?

Reply
  • Hey Rachel — great question, and honestly this is something we could document better. Short answer: we don't currently support fine-grained scopes on API keys. A key is either valid (full access based on the account's feature tier) or it's not.

    The auth model right now is basically:

    • Your API key inherits the permissions of the user account that created it
    • There's no "read-only" key type or endpoint-level restrictions

    That said, for your use case, here are the workarounds I see teams use:

    Option 1: Service Account with Restricted User Role

    Create a dedicated user account in FieldPulse with the Viewer role (or custom role with "View" permissions only), then generate the API key from that account. The key will still technically be able to call POST/PUT endpoints, but the underlying user permissions will block mutations. You'll get 403s on write attempts, which is ... not elegant, but functional.

    Option 2: Reverse Proxy with Request Filtering

    Some teams put a lightweight proxy (nginx, AWS API Gateway, etc.) in front of our API that rejects anything except GET requests. Yeah, this is infrastructure you have to maintain, but it gives you surgical control.

    What we're actually building

    Scoped API keys with explicit read/write and resource-level permissions are on the roadmap for Q1 2026. I can't share the full spec yet, but think along the lines of:

    {
      "name": "Data Warehouse Sync",
      "scopes": ["work_orders:read", "customers:read"],
      "allowed_ips": ["10.0.0.0/8"]
    }

    No promises on exact syntax, but that's the direction.

    For now, I'd recommend Option 1 — it's what most of our Enterprise customers do for read-only ETL jobs. Want me to walk through setting up a restricted service account?

Children
  • Thank you for the detailed response, Eli. I have confirmed that Option 1 works as described. I created a service account with the "Viewer" role and generated a new API key. I tested the following:

    • GET /v1/work_orders — returns 200 with expected payload
    • POST /v1/work_orders — returns 403 with message "User does not have permission to create work orders"

    This satisfies our security requirements for the data warehouse sync. I will proceed with this configuration.

    I have noted the Q1 2026 roadmap item — is there a public feature request or beta list we can join to track progress on scoped API keys?

  • Awesome, glad that unblocked you. For the beta — shoot me a DM with your account ID and I'll flag you for the early access list when we start private previews. Probably late Q4 2025.

    One heads up: the Viewer role blocking writes is Working As IntendedTm but not officially guaranteed behavior, since the API key itself still has "full" scope in a sense. I wouldn't build critical security logic around it without monitoring. If someone accidentally bumps that service account to Manager, your sync suddenly has write access.

    Consider adding a cheap safety check in your Python wrapper — something like:

    def validate_read_only(self, method):
        if method != 'GET' and not self.allow_writes:
            raise ValueError(f"Read-only client rejected {method} request")

    Defense in depth, etc etc.