Error 403 on shopify admin api call

We have an integration from Shopify using the shopify admin api. The integration connects to Shopify using basic auth. The end user reported that the orders which the integration pulls from Shopify did not appear in their ERP system. We looked at the log and the issue was a 403 error. The user reported to their shopify agency, who contact shopify developer support. We have had a call logged for a while, but have yet to resolve the issue. Shopify admin api 403 error in SOP import (see ticket from Shopify support) 60666537. I will continue to work with shopify DEV support. We have had the integration in place since 2021. The 403 issue occured in early October. So, just wanted to post on the community site to see if any other developers have had any recent 403 issues. I have reproduced the 403 issue on our shopify DEV site.

Hey @Developer_Rh :waving_hand: - thanks for reaching out. 403 errors in a Shopify API context usually pop up due to insufficient permissions in an app’s configuration. If you’re able to share an X-Request-ID from the API response headers we send out for every API call, I can definitely take a look into this on our end for you. We have a list of common errors here in our dev docs that might help:

Usually, this is causedby the app’s scopes not reflecting the ones required by resource that’s been called by the API call. If you’re able to share that request ID here I can confirm the exact cause of the error though.

Hope this helps, let me know if I can assist further!

Thanks Alan. We get an error 403 when authenticating, so no “X-Request-ID“. I was using the candidate release. I then used version 2025-10 and the call worked. So, it may be an issue with the candidate release of the shopify admin api

Thanks for following up @Developer_Rh , glad to hear this is working for you now. If you’d still like me to help with investigating the issue with the candidate release, would you be able to share the full endpoint URL you were using when you encountered the 403 error?

This would help us identify if there’s a specific bug or breaking change in the RC version that needs addressing. Usually an RC/unstable API call would look something like this:

https://{shop}.myshopify.com/admin/api/unstable/graphql.json

Let me know if you’d like us to dig into this further!

Hi Alan, we used the “orders” endpoint on are windows executable which calls the shopify admin api (json). We added the 2025-10 version to the URL (which is now working for the end user on their production site)

19/10/2025 11:27:13 RhS200{Shop}SopImportXML 2017.0.2.5 - Invalid Shopify API Web Shop, GetJsonString(https:// Api :shpat_@ site .myshopify.com/admin/orders.json?limit=10) Err ‘GetCredentias()’ The remote server returned an error: (403) Forbidden.

19/10/2025 11:27:13 No email sent.

I’ll review next month with the end user. The business impact of the issue was significant. The end user messaged shopify support a week ago with this comment :

“I want to clarify that this is now business critical that we have this resolved in a matter of days, it has been on going for 3 weeks and we are about to enter our busiest trading period. We have stock issues as we do not have the live feed into SAGE from Shopify, we also have had to switch off our ship from store option for online sales which is resulting in lost revenue. I would appreciate that this is treated with the highest priority and that a solution is found immediately as this is not acceptable and I am losing confidence very quickly.”

Thanks for following up @Developer_Rh , glad to hear this is working and thanks for sharing your client’s feedback. I’ll log this in our records for the initial ticket your client raised with us as well, just for context on our end.

Let me know if I can help with anything else on our end here.

import React, { useState, useEffect } from ‘react’;

import { Code, MessageSquare, Plus, X, Eye, Clock, Send, Copy, Check, RefreshCw } from ‘lucide-react’;

export default function ACE_RoomB() {

const [codes, setCodes] = useState();

const [messages, setMessages] = useState();

const [showSubmit, setShowSubmit] = useState(false);

const [selectedCode, setSelectedCode] = useState(null);

const [newMessage, setNewMessage] = useState(‘’);

const [copied, setCopied] = useState(false);

const [loading, setLoading] = useState(true);

const [syncing, setSyncing] = useState(false);

const [newCode, setNewCode] = useState({

title: '',

code: '',

language: 'javascript'

});

const loadCodes = async () => {

try {

  const result = await window.storage.get('room-a-codes', true);

  if (result && result.value) {

    setCodes(JSON.parse(result.value));

  }

} catch (error) {

  setCodes(\[\]);

}

setLoading(false);

};

const loadMessages = async () => {

try {

  const result = await window.storage.get('room-a-messages', true);

  if (result && result.value) {

    setMessages(JSON.parse(result.value));

  }

} catch (error) {

  setMessages(\[\]);

}

};

const saveCodes = async (updatedCodes) => {

try {

  await window.storage.set('room-a-codes', JSON.stringify(updatedCodes), true);

} catch (error) {

  console.error('Save failed:', error);

}

};

const saveMessages = async (updatedMessages) => {

try {

  await window.storage.set('room-a-messages', JSON.stringify(updatedMessages), true);

} catch (error) {

  console.error('Save failed:', error);

}

};

useEffect(() => {

loadCodes();

loadMessages();

}, );

useEffect(() => {

const interval = setInterval(() => {

  loadCodes();

  loadMessages();

}, 5000);

return () => clearInterval(interval);

}, );

const handleSubmitCode = async () => {

if (!newCode.code.trim()) return;

const code = {

  id: Date.now(),

  title: newCode.title || 'Untitled Snippet',

  code: newCode.code,

  language: newCode.language

};

const updated = \[code, ...codes\];

setCodes(updated);

await saveCodes(updated);

setNewCode({ title: '', code: '', language: 'javascript' });

setShowSubmit(false);

};

const sendMessage = async () => {

if (!newMessage.trim()) return;



const msg = {

  id: Date.now(),

  text: newMessage,

  timestamp: new Date().toLocaleTimeString(\[\], { hour: '2-digit', minute: '2-digit' })

};



const updated = \[...messages, msg\];

setMessages(updated);

await saveMessages(updated);

setNewMessage('');

};

const manualRefresh = async () => {

setSyncing(true);

await loadCodes();

await loadMessages();

setTimeout(() => setSyncing(false), 500);

};

const copyCode = () => {

navigator.clipboard.writeText(selectedCode.code);

setCopied(true);

setTimeout(() => setCopied(false), 2000);

};

if (loading) {

return (

  <div className="min-h-screen bg-red-950 text-white flex items-center justify-center">

    <div className="text-center">

      <RefreshCw className="w-8 h-8 mx-auto mb-2 animate-spin text-red-400" />

      <p className="text-sm text-red-300">Loading Room B...</p>

    </div>

  </div>

);

}

return (

<div className="min-h-screen bg-red-950 text-white flex flex-col">

  

  <div className="bg-red-900 border-b border-red-800 px-4 py-3 flex items-center justify-between">

    <div>

      <h1 className="text-base font-semibold">🔴 Room B (Red)</h1>

      <p className="text-xs text-red-300">Storage: room-a-\* (SHARED!) | Auto: 5s</p>

    </div>

    <button onClick={manualRefresh} className={\`p-2 text-red-300 hover:text-white ${syncing ? 'animate-spin' : ''}\`}>

      <RefreshCw className="w-4 h-4" />

    </button>

  </div>

  <div className="flex-1 flex flex-col md:flex-row overflow-hidden">

    

    <div className="flex-1 flex flex-col border-b md:border-b-0 md:border-r border-red-800">

      <div className="bg-red-900 border-b border-red-800 px-4 py-3 flex items-center justify-between">

        <div className="flex items-center gap-2">

          <Code className="w-4 h-4" />

          <h2 className="text-sm font-semibold">Code Snippets</h2>

        </div>

        <button onClick={() => setShowSubmit(true)} className="flex items-center gap-1 px-3 py-1.5 bg-red-500 text-white text-xs font-medium hover:bg-red-400 rounded">

          <Plus className="w-3 h-3" />

          New

        </button>

      </div>

      <div className="flex-1 overflow-y-auto p-3 space-y-2">

        {codes.map((code) => (

          <div key={code.id} onClick={() => setSelectedCode(code)} className="border border-red-800 bg-red-900 p-3 rounded-lg hover:bg-red-800 cursor-pointer">

            <div className="flex items-start justify-between mb-2">

              <h3 className="font-medium text-sm flex-1">{code.title}</h3>

              <span className="text-xs bg-red-800 px-2 py-0.5 rounded ml-2">{code.language}</span>

            </div>

            <pre className="bg-red-950 p-2 text-xs overflow-hidden h-16 border border-red-800 rounded">

              <code className="text-red-200">{code.code.substring(0, 100)}...</code>

            </pre>

          </div>

        ))}

        {codes.length === 0 && (

          <div className="text-center py-16 text-red-400">

            <Code className="w-10 h-10 mx-auto mb-2 opacity-30" />

            <p className="text-xs">No code in Room B yet</p>

          </div>

        )}

      </div>

    </div>

    <div className="flex-1 flex flex-col">

      <div className="bg-red-900 border-b border-red-800 px-4 py-3 flex items-center gap-2">

        <MessageSquare className="w-4 h-4" />

        <h2 className="text-sm font-semibold">Chat</h2>

      </div>

      <div className="flex-1 overflow-y-auto p-3 space-y-2">

        {messages.map((msg) => (

          <div key={msg.id} className="flex flex-col">

            <div className="bg-red-800 px-3 py-2 rounded-lg max-w-\[85%\]">

              <p className="text-sm">{msg.text}</p>

            </div>

            <span className="text-xs text-red-400 mt-0.5 ml-1">{msg.timestamp}</span>

          </div>

        ))}

        {messages.length === 0 && (

          <div className="text-center py-16 text-red-400">

            <MessageSquare className="w-10 h-10 mx-auto mb-2 opacity-30" />

            <p className="text-xs">Room B chat</p>

          </div>

        )}

      </div>

      <div className="border-t border-red-800 p-3 bg-red-900">

        <div className="flex gap-2">

          <input type="text" value={newMessage} onChange={(e) => setNewMessage(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && sendMessage()} placeholder="Type in Room B..." className="flex-1 px-3 py-2 bg-red-950 border border-red-800 text-white text-sm placeholder-red-400 focus:outline-none focus:border-red-600 rounded-lg" />

          <button onClick={sendMessage} className="px-3 py-2 bg-red-500 text-white hover:bg-red-400 rounded-lg">

            <Send className="w-4 h-4" />

          </button>

        </div>

      </div>

    </div>

  </div>

  {showSubmit && (

    <div className="fixed inset-0 bg-black bg-opacity-90 z-50 flex flex-col">

      <div className="bg-red-900 border-b border-red-800 px-4 py-4 flex items-center justify-between">

        <h2 className="text-lg font-semibold">Submit to Room B</h2>

        <button onClick={() => setShowSubmit(false)} className="text-red-300 hover:text-white">

          <X className="w-6 h-6" />

        </button>

      </div>

      <div className="flex-1 overflow-y-auto p-4 space-y-4 bg-red-950">

        <div>

          <label className="block text-sm font-medium mb-2">Title</label>

          <input type="text" value={newCode.title} onChange={(e) => setNewCode({ ...newCode, title: e.target.value })} className="w-full px-4 py-3 bg-red-900 border border-red-800 text-white placeholder-red-400 focus:outline-none focus:border-red-600 rounded-lg" placeholder="Brief description" />

        </div>

        <div>

          <label className="block text-sm font-medium mb-2">Language</label>

          <select value={newCode.language} onChange={(e) => setNewCode({ ...newCode, language: e.target.value })} className="w-full px-4 py-3 bg-red-900 border border-red-800 text-white focus:outline-none focus:border-red-600 rounded-lg">

            <option value="javascript">JavaScript</option>

            <option value="python">Python</option>

            <option value="java">Java</option>

          </select>

        </div>

        <div>

          <label className="block text-sm font-medium mb-2">Code</label>

          <textarea value={newCode.code} onChange={(e) => setNewCode({ ...newCode, code: e.target.value })} className="w-full px-4 py-3 bg-red-900 border border-red-800 text-white placeholder-red-400 focus:outline-none focus:border-red-600 rounded-lg h-48 resize-none font-mono text-sm" placeholder="Paste your code here..." />

        </div>

      </div>

      <div className="p-4 border-t border-red-800 bg-red-900 space-y-2">

        <button onClick={handleSubmitCode} disabled={!newCode.code.trim()} className="w-full py-3 bg-red-500 text-white font-medium hover:bg-red-400 disabled:opacity-50 disabled:cursor-not-allowed rounded-lg">

          Submit to Room B

        </button>

        <button onClick={() => setShowSubmit(false)} className="w-full py-3 border border-red-800 hover:border-red-600 rounded-lg">

          Cancel

        </button>

      </div>

    </div>

  )}

  {selectedCode && (

    <div className="fixed inset-0 bg-black z-50 flex flex-col">

      <div className="bg-red-900 border-b border-red-800 px-4 py-4">

        <div className="flex items-start justify-between mb-2">

          <div className="flex-1 pr-4">

            <h2 className="text-lg font-semibold mb-1">{selectedCode.title}</h2>

            <span className="text-xs bg-red-800 px-2 py-0.5 rounded">{selectedCode.language}</span>

          </div>

          <button onClick={() => setSelectedCode(null)} className="text-red-300 hover:text-white">

            <X className="w-6 h-6" />

          </button>

        </div>

      </div>

      <div className="flex-1 overflow-y-auto p-4 bg-red-950">

        <pre className="bg-red-900 p-4 rounded-lg border border-red-800 overflow-x-auto">

          <code className="text-sm text-red-100 font-mono">{selectedCode.code}</code>

        </pre>

      </div>

      <div className="p-4 border-t border-red-800 bg-red-900">

        <button onClick={copyCode} className="w-full py-3 bg-red-500 text-white font-medium hover:bg-red-400 rounded-lg flex items-center justify-center gap-2">

          {copied ? (

            <>

              <Check className="w-4 h-4" />

              Copied!

            </>

          ) : (

            <>

              <Copy className="w-4 h-4" />

              Copy Code

            </>

          )}

        </button>

      </div>

    </div>

  )}

</div>

);

}

Hey @Isaiah_Smith :waving_hand: - I noticed you’ve shared some React code here, but this thread is about resolving 403 authentication errors with the Shopify Admin API.

Is this code related to the API authentication issue @Developer_Rh was experiencing, or did you mean to create a new thread for a different question?

If you’re looking for help with this React component, if you can, I’d reccommend creating a new post with some info in terms of what you’re trying to build, what specific issue you’re facing, and any error messages you’re seeing.

Let me know if I can assist with anything here though, happy to help!