[{"data":1,"prerenderedAt":610},["ShallowReactive",2],{"seite-\u002Fratgeber\u002Fbexio-api-wordpress\u002F":3},{"id":4,"title":5,"body":6,"description":601,"extension":602,"meta":603,"navigation":604,"path":605,"robots":606,"seo":607,"stem":608,"__hash__":609},"seiten_de\u002Fratgeber\u002Fbexio-api-wordpress.md","bexio API mit WordPress verbinden, Anleitung mit OAuth, Token und Endpunkten",{"type":7,"value":8,"toc":591},"minimark",[9,14,18,23,28,60,67,71,93,96,100,107,202,209,220,224,231,243,246,250,253,292,295,425,429,495,499,555,558,562,565,581,587],[10,11,13],"h1",{"id":12},"bexio-api-mit-wordpress-verbinden","bexio API mit WordPress verbinden",[15,16,17],"p",{},"Eine Anfrage aus dem Website-Formular soll als Kontakt in bexio landen, eine Bestellung als\nRechnung, ein Kunde aus dem Shop als Adresse. Dafür muss WordPress mit der bexio API sprechen.\nDiese Anleitung zeigt den Weg von der App im Developer Portal bis zum ersten angelegten\nKontakt, die Fallen unterwegs und wann sich ein fertiges Plugin mehr lohnt als eigener Code.",[19,20],"produkt-ablauf",{":schritte":21,"titel":22},"[{\"ort\":\"Website-Formular\",\"text\":\"Besucher schickt eine Anfrage ab\"},{\"ort\":\"WordPress\",\"text\":\"Plugin oder eigener Code mit Token\",\"eigen\":true},{\"ort\":\"auth.bexio.com\",\"text\":\"Token per OAuth 2, regelmässig erneuert\"},{\"ort\":\"api.bexio.com\",\"text\":\"Kontakt suchen oder anlegen, Notiz anhängen\"}]","Ablauf: Das Website-Formular schickt die Anfrage an WordPress, WordPress holt sich ein Token bei auth.bexio.com und legt über api.bexio.com Kontakt und Notiz an",[24,25,27],"h2",{"id":26},"was-die-bexio-api-ist","Was die bexio API ist",[15,29,30,31,35,36,39,40,43,44,47,48,51,52,59],{},"Die bexio API ist eine REST-Schnittstelle mit JSON. Alle Endpunkte liegen unter\n",[32,33,34],"code",{},"https:\u002F\u002Fapi.bexio.com",", die Pfade beginnen je nach Bereich mit ",[32,37,38],{},"\u002F2.0\u002F",", ",[32,41,42],{},"\u002F3.0\u002F"," oder neuer,\netwa ",[32,45,46],{},"\u002F2.0\u002Fcontact"," für Kontakte und ",[32,49,50],{},"\u002F3.0\u002Fusers\u002Fme"," für den angemeldeten Benutzer. Die\nReferenz steht unter ",[53,54,58],"a",{"href":55,"rel":56},"https:\u002F\u002Fdocs.bexio.com\u002F",[57],"nofollow","docs.bexio.com",". Eine OpenAPI-Beschreibung\nbietet bexio laut eigener Doku nicht an, ein Client entsteht also von Hand.",[15,61,62,63,66],{},"Jeder Zugriff braucht ein Access-Token im Header ",[32,64,65],{},"Authorization: Bearer …",". Wie WordPress\nzu diesem Token kommt, ist der eigentliche Aufwand.",[24,68,70],{"id":69},"schritt-1-app-im-developer-portal-anlegen","Schritt 1: App im Developer Portal anlegen",[72,73,74,84,87,90],"ol",{},[75,76,77,78,83],"li",{},"Im ",[53,79,82],{"href":80,"rel":81},"https:\u002F\u002Fdeveloper.bexio.com\u002F",[57],"Developer Portal"," mit dem bexio-Konto anmelden.",[75,85,86],{},"Die Nutzungsbedingungen lesen und annehmen, besonders Ziffer 4.4 zur kommerziellen Nutzung\n(siehe Stolperfallen).",[75,88,89],{},"Eine neue App anlegen und die Redirect-URL eintragen, auf die bexio nach der Anmeldung\nzurückleitet, etwa die Einstellungsseite des Plugins im WordPress-Backend. Bis zu zehn\nAdressen sind möglich, zum Beispiel für Test und Produktion.",[75,91,92],{},"Unter «App Details» Client-ID und Client-Secret ablesen.",[15,94,95],{},"Das Client-Secret gehört auf den Server, nie in JavaScript im Browser.",[24,97,99],{"id":98},"schritt-2-anmelden-mit-oauth-2","Schritt 2: Anmelden mit OAuth 2",[15,101,102,103,106],{},"bexio meldet über OpenID Connect auf ",[32,104,105],{},"auth.bexio.com"," an, mit dem «Authorization Code Flow».\nWordPress schickt den Benutzer dazu auf die Anmeldeseite von bexio:",[108,109,114],"pre",{"className":110,"code":111,"language":112,"meta":113,"style":113},"language-bash shiki shiki-themes github-light github-dark","https:\u002F\u002Fauth.bexio.com\u002Frealms\u002Fbexio\u002Fprotocol\u002Fopenid-connect\u002Fauth\n  ?client_id=\u003CClient-ID>\n  &redirect_uri=\u003Ceingetragene Redirect-URL>\n  &response_type=code\n  &scope=openid offline_access contact_edit note_edit\n  &state=\u003CZufallswert>\n","bash","",[32,115,116,125,139,158,169,189],{"__ignoreMap":113},[117,118,121],"span",{"class":119,"line":120},"line",1,[117,122,124],{"class":123},"sScJk","https:\u002F\u002Fauth.bexio.com\u002Frealms\u002Fbexio\u002Fprotocol\u002Fopenid-connect\u002Fauth\n",[117,126,128,131,135],{"class":119,"line":127},2,[117,129,130],{"class":123},"  ?client_id",[117,132,134],{"class":133},"sZZnC","=",[117,136,138],{"class":137},"sVt8B","\u003CClient-ID>\n",[117,140,142,145,149,152,155],{"class":119,"line":141},3,[117,143,144],{"class":137},"  &redirect_uri",[117,146,148],{"class":147},"szBVR","=\u003C",[117,150,151],{"class":133},"eingetragene",[117,153,154],{"class":123}," Redirect-URL",[117,156,157],{"class":137},">\n",[117,159,161,164,166],{"class":119,"line":160},4,[117,162,163],{"class":137},"  &response_type",[117,165,134],{"class":147},[117,167,168],{"class":133},"code\n",[117,170,172,175,177,180,183,186],{"class":119,"line":171},5,[117,173,174],{"class":137},"  &scope",[117,176,134],{"class":147},[117,178,179],{"class":133},"openid",[117,181,182],{"class":123}," offline_access",[117,184,185],{"class":133}," contact_edit",[117,187,188],{"class":133}," note_edit\n",[117,190,192,195,197,200],{"class":119,"line":191},6,[117,193,194],{"class":137},"  &state",[117,196,148],{"class":147},[117,198,199],{"class":133},"Zufallswert",[117,201,157],{"class":147},[15,203,204,205,208],{},"Der Benutzer meldet sich an und bestätigt die Rechte. bexio leitet mit einem Code zurück,\nWordPress tauscht ihn zusammen mit Client-ID und Secret beim Token-Endpunkt\n",[32,206,207],{},"\u002Frealms\u002Fbexio\u002Fprotocol\u002Fopenid-connect\u002Ftoken"," gegen Access- und Refresh-Token.",[15,210,211,212,215,216,219],{},"Zu den Scopes: Ein Schreibrecht schliesst das Leserecht ein, ",[32,213,214],{},"contact_edit"," reicht also auch\nzum Suchen. ",[32,217,218],{},"offline_access"," braucht es für das Refresh-Token. Und die API arbeitet immer mit\nden Rechten des Benutzers, der die Verbindung hergestellt hat: Darf er in bexio keine Kontakte\nsehen, darf es die App auch nicht.",[24,221,223],{"id":222},"schritt-3-token-speichern-und-erneuern","Schritt 3: Token speichern und erneuern",[15,225,226,227,230],{},"Das Access-Token läuft nach kurzer Zeit ab. Vorher holt WordPress mit dem Refresh-Token und\n",[32,228,229],{},"grant_type=refresh_token"," ein neues, alle Werte im Body der Anfrage, nicht in der URL. Dabei\ngilt:",[232,233,234,237,240],"ul",{},[75,235,236],{},"Immer das neue Refresh-Token speichern, das bei der Erneuerung zurückkommt.",[75,238,239],{},"Bleibt eine Verbindung ein Jahr lang ohne Erneuerung, schliesst bexio die Sitzung; danach\nmuss sich jemand neu anmelden.",[75,241,242],{},"Tokens in WordPress-Optionen ohne Autoload ablegen, damit sie nicht bei jedem Seitenaufruf\nmitgeladen werden.",[15,244,245],{},"Für eigene Skripte gibt es ausserdem persönliche Zugriffstoken (PAT). Sie haben vollen Zugriff\nauf alle Daten der Firma und gelten 60 Tage. Für den eigenen Gebrauch sind sie bequem, für ein\nPlugin auf einer Kundenwebsite taugen sie nicht.",[24,247,249],{"id":248},"schritt-4-kontakt-und-notiz-anlegen","Schritt 4: Kontakt und Notiz anlegen",[15,251,252],{},"Ein typischer Ablauf für eine Formularanfrage braucht vier Aufrufe:",[72,254,255,269,275,286],{},[75,256,257,260,261,264,265,268],{},[32,258,259],{},"GET \u002F3.0\u002Fusers\u002Fme"," liefert die ID des Benutzers. Sie ist beim Anlegen Pflicht, als\n",[32,262,263],{},"user_id"," und ",[32,266,267],{},"owner_id",".",[75,270,271,274],{},[32,272,273],{},"POST \u002F2.0\u002Fcontact\u002Fsearch"," sucht über die E-Mail-Adresse, ob es den Kontakt schon gibt.",[75,276,277,278,281,282,285],{},"Falls nicht: ",[32,279,280],{},"POST \u002F2.0\u002Fcontact"," legt ihn an, ",[32,283,284],{},"contact_type_id"," 1 für Firmen, 2 für\nPersonen.",[75,287,288,291],{},[32,289,290],{},"POST \u002F2.0\u002Fnote"," hängt den Formulartext als Notiz an den Kontakt.",[15,293,294],{},"Der Aufruf zum Anlegen einer Firma sieht so aus:",[108,296,300],{"className":297,"code":298,"language":299,"meta":113,"style":113},"language-json shiki shiki-themes github-light github-dark","{\n  \"contact_type_id\": 1,\n  \"name_1\": \"Muster AG\",\n  \"street_name\": \"Bahnhofstrasse\",\n  \"house_number\": \"1\",\n  \"postcode\": \"8001\",\n  \"city\": \"Zürich\",\n  \"mail\": \"info@muster.ch\",\n  \"user_id\": 1,\n  \"owner_id\": 1\n}\n","json",[32,301,302,307,322,334,346,358,370,383,396,408,419],{"__ignoreMap":113},[117,303,304],{"class":119,"line":120},[117,305,306],{"class":137},"{\n",[117,308,309,313,316,319],{"class":119,"line":127},[117,310,312],{"class":311},"sj4cs","  \"contact_type_id\"",[117,314,315],{"class":137},": ",[117,317,318],{"class":311},"1",[117,320,321],{"class":137},",\n",[117,323,324,327,329,332],{"class":119,"line":141},[117,325,326],{"class":311},"  \"name_1\"",[117,328,315],{"class":137},[117,330,331],{"class":133},"\"Muster AG\"",[117,333,321],{"class":137},[117,335,336,339,341,344],{"class":119,"line":160},[117,337,338],{"class":311},"  \"street_name\"",[117,340,315],{"class":137},[117,342,343],{"class":133},"\"Bahnhofstrasse\"",[117,345,321],{"class":137},[117,347,348,351,353,356],{"class":119,"line":171},[117,349,350],{"class":311},"  \"house_number\"",[117,352,315],{"class":137},[117,354,355],{"class":133},"\"1\"",[117,357,321],{"class":137},[117,359,360,363,365,368],{"class":119,"line":191},[117,361,362],{"class":311},"  \"postcode\"",[117,364,315],{"class":137},[117,366,367],{"class":133},"\"8001\"",[117,369,321],{"class":137},[117,371,373,376,378,381],{"class":119,"line":372},7,[117,374,375],{"class":311},"  \"city\"",[117,377,315],{"class":137},[117,379,380],{"class":133},"\"Zürich\"",[117,382,321],{"class":137},[117,384,386,389,391,394],{"class":119,"line":385},8,[117,387,388],{"class":311},"  \"mail\"",[117,390,315],{"class":137},[117,392,393],{"class":133},"\"info@muster.ch\"",[117,395,321],{"class":137},[117,397,399,402,404,406],{"class":119,"line":398},9,[117,400,401],{"class":311},"  \"user_id\"",[117,403,315],{"class":137},[117,405,318],{"class":311},[117,407,321],{"class":137},[117,409,411,414,416],{"class":119,"line":410},10,[117,412,413],{"class":311},"  \"owner_id\"",[117,415,315],{"class":137},[117,417,418],{"class":311},"1\n",[117,420,422],{"class":119,"line":421},11,[117,423,424],{"class":137},"}\n",[24,426,428],{"id":427},"typische-stolperfallen","Typische Stolperfallen",[232,430,431,438,444,460,470,483,489],{},[75,432,433,437],{},[434,435,436],"strong",{},"Redirect-URL:"," Sie muss genau so im Developer Portal stehen, sonst bricht die Anmeldung\nmit einer Fehlermeldung ab.",[75,439,440,443],{},[434,441,442],{},"Neue Scopes:"," Die Rechte einer Verbindung ändern sich bei der Erneuerung nicht. Braucht\ndie App mehr, muss sich der Benutzer neu anmelden.",[75,445,446,449,450,453,454,264,457,268],{},[434,447,448],{},"Adressfelder:"," Das Feld ",[32,451,452],{},"address"," ist beim Anlegen veraltet. Strasse und Hausnummer\ngehören in ",[32,455,456],{},"street_name",[32,458,459],{},"house_number",[75,461,462,465,466,469],{},[434,463,464],{},"Zeilenumbrüche in Notizen:"," bexio zeigt den Text einer Notiz ohne Zeilenumbrüche an.\nWer Absätze will, setzt ",[32,467,468],{},"\u003Cbr>"," und maskiert die Werte als HTML.",[75,471,472,475,476,264,479,482],{},[434,473,474],{},"Ratenlimit:"," Zu viele Anfragen pro Minute beantwortet die API mit Status 429. Die Header\n",[32,477,478],{},"RateLimit-Remaining",[32,480,481],{},"RateLimit-Reset"," sagen, wie lange zu warten ist.",[75,484,485,488],{},[434,486,487],{},"Langsame Formulare:"," Wer bexio direkt beim Absenden aufruft, lässt den Besucher warten\nund verliert die Anfrage, wenn bexio gerade nicht antwortet. Besser im Hintergrund\nübertragen und bei Fehlern wiederholen.",[75,490,491,494],{},[434,492,493],{},"Kommerzielle Nutzung:"," Laut Ziffer 4.4 der Bedingungen muss bexio informiert werden, wer\nauf der API ein eigenes Geschäftsmodell betreibt, an das mindestens fünf bexio-Konten\nangeschlossen sind.",[24,496,498],{"id":497},"drei-wege-im-vergleich","Drei Wege im Vergleich",[500,501,502,518],"table",{},[503,504,505],"thead",{},[506,507,508,512,515],"tr",{},[509,510,511],"th",{},"Weg",[509,513,514],{},"Passt, wenn",[509,516,517],{},"Zu bedenken",[519,520,521,533,544],"tbody",{},[506,522,523,527,530],{},[524,525,526],"td",{},"Selbst bauen",[524,528,529],{},"eigene Entwickler da sind und der Ablauf sehr speziell ist",[524,531,532],{},"Anmeldung, Token-Erneuerung, Fehlerbehandlung und Updates bleiben dauerhaft eigene Arbeit",[506,534,535,538,541],{},[524,536,537],{},"Zapier oder Make",[524,539,540],{},"schon andere Abläufe dort laufen",[524,542,543],{},"ein weiterer Dienst, über den die Formulardaten fliessen, Zuordnung und Duplikate von Hand",[506,545,546,549,552],{},[524,547,548],{},"Fertiges Plugin",[524,550,551],{},"der Ablauf einem gängigen Muster folgt",[524,553,554],{},"weniger frei als eigener Code",[15,556,557],{},"Make und Zapier bieten bexio als eigene App an. Das Formular-Plugin schickt die Anfrage per\nWebhook dorthin, und eine bexio-Aktion legt den Kontakt an.",[24,559,561],{"id":560},"fertige-lösungen","Fertige Lösungen",[15,563,564],{},"Für die zwei häufigsten Fälle gibt es meine Anbindungen:",[232,566,567,574],{},[75,568,569,573],{},[53,570,572],{"href":571},"\u002Fbexio-formular-connector\u002F","bexio-Formular-Connector",": WordPress-Plugin, Anfragen aus dem\nWebsite-Formular werden zu Kontakten mit Notiz in bexio, Duplikate werden an der E-Mail\nerkannt. Jeder Betreiber verbindet sein bexio über eine eigene App, die Daten gehen direkt\nvon der Website zu bexio.",[75,575,576,580],{},[53,577,579],{"href":578},"\u002Fbexio-hubspot\u002F","bexio ↔ HubSpot",": Ein gewonnener Deal in HubSpot wird zur Offerte oder\nRechnung in bexio, der Zahlungsstand kommt zurück in den Deal.",[15,582,583],{},[53,584,586],{"href":585},"\u002Fratgeber\u002F","Alle Ratgeber",[588,589,590],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":113,"searchDepth":127,"depth":127,"links":592},[593,594,595,596,597,598,599,600],{"id":26,"depth":127,"text":27},{"id":69,"depth":127,"text":70},{"id":98,"depth":127,"text":99},{"id":222,"depth":127,"text":223},{"id":248,"depth":127,"text":249},{"id":427,"depth":127,"text":428},{"id":497,"depth":127,"text":498},{"id":560,"depth":127,"text":561},"bexio API mit WordPress verbinden: App im Developer Portal anlegen, Anmeldung über OAuth 2, Token erneuern, Kontakte und Notizen anlegen. Dazu typische Stolperfallen und drei Wege im Vergleich.","md",{},true,"\u002Fratgeber\u002Fbexio-api-wordpress",null,{"title":5,"description":601},"ratgeber\u002Fbexio-api-wordpress","BeGJWveYufO-jMRWMM9yEYGpK8KuNM5cfMHxbhV8dwQ",1791118315794]